diff options
Diffstat (limited to 'drivers/gpu/drm/imx/dcss/dcss-kms.c')
-rw-r--r-- | drivers/gpu/drm/imx/dcss/dcss-kms.c | 135 |
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, +}; |