From 2c3c1048746a4622d8c89a29670120dc8fab93c4 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:49:45 +0200 Subject: Adding upstream version 6.1.76. Signed-off-by: Daniel Baumann --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 240 +++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 drivers/gpu/drm/exynos/exynos_drm_crtc.c (limited to 'drivers/gpu/drm/exynos/exynos_drm_crtc.c') diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c new file mode 100644 index 000000000..d19e796c2 --- /dev/null +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* exynos_drm_crtc.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Authors: + * Inki Dae + * Joonyoung Shim + * Seung-Woo Kim + */ + +#include +#include +#include +#include +#include + +#include "exynos_drm_crtc.h" +#include "exynos_drm_drv.h" +#include "exynos_drm_plane.h" + +static void exynos_drm_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + + if (exynos_crtc->ops->atomic_enable) + exynos_crtc->ops->atomic_enable(exynos_crtc); + + drm_crtc_vblank_on(crtc); +} + +static void exynos_drm_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + + drm_crtc_vblank_off(crtc); + + if (exynos_crtc->ops->atomic_disable) + exynos_crtc->ops->atomic_disable(exynos_crtc); + + spin_lock_irq(&crtc->dev->event_lock); + if (crtc->state->event && !crtc->state->active) { + drm_crtc_send_vblank_event(crtc, crtc->state->event); + crtc->state->event = NULL; + } + spin_unlock_irq(&crtc->dev->event_lock); +} + +static int exynos_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, + crtc); + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + + if (!crtc_state->enable) + return 0; + + if (exynos_crtc->ops->atomic_check) + return exynos_crtc->ops->atomic_check(exynos_crtc, crtc_state); + + return 0; +} + +static void exynos_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + + if (exynos_crtc->ops->atomic_begin) + exynos_crtc->ops->atomic_begin(exynos_crtc); +} + +static void exynos_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + + if (exynos_crtc->ops->atomic_flush) + exynos_crtc->ops->atomic_flush(exynos_crtc); +} + +static enum drm_mode_status exynos_crtc_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) +{ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + + if (exynos_crtc->ops->mode_valid) + return exynos_crtc->ops->mode_valid(exynos_crtc, mode); + + return MODE_OK; +} + +static bool exynos_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + + if (exynos_crtc->ops->mode_fixup) + return exynos_crtc->ops->mode_fixup(exynos_crtc, mode, + adjusted_mode); + + return true; +} + + +static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { + .mode_valid = exynos_crtc_mode_valid, + .mode_fixup = exynos_crtc_mode_fixup, + .atomic_check = exynos_crtc_atomic_check, + .atomic_begin = exynos_crtc_atomic_begin, + .atomic_flush = exynos_crtc_atomic_flush, + .atomic_enable = exynos_drm_crtc_atomic_enable, + .atomic_disable = exynos_drm_crtc_atomic_disable, +}; + +void exynos_crtc_handle_event(struct exynos_drm_crtc *exynos_crtc) +{ + struct drm_crtc *crtc = &exynos_crtc->base; + struct drm_pending_vblank_event *event = crtc->state->event; + unsigned long flags; + + if (!event) + return; + crtc->state->event = NULL; + + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + + spin_lock_irqsave(&crtc->dev->event_lock, flags); + drm_crtc_arm_vblank_event(crtc, event); + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); +} + +static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) +{ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + + drm_crtc_cleanup(crtc); + kfree(exynos_crtc); +} + +static int exynos_drm_crtc_enable_vblank(struct drm_crtc *crtc) +{ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + + if (exynos_crtc->ops->enable_vblank) + return exynos_crtc->ops->enable_vblank(exynos_crtc); + + return 0; +} + +static void exynos_drm_crtc_disable_vblank(struct drm_crtc *crtc) +{ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + + if (exynos_crtc->ops->disable_vblank) + exynos_crtc->ops->disable_vblank(exynos_crtc); +} + +static const struct drm_crtc_funcs exynos_crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .destroy = exynos_drm_crtc_destroy, + .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 = exynos_drm_crtc_enable_vblank, + .disable_vblank = exynos_drm_crtc_disable_vblank, +}; + +struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, + struct drm_plane *plane, + enum exynos_drm_output_type type, + const struct exynos_drm_crtc_ops *ops, + void *ctx) +{ + struct exynos_drm_crtc *exynos_crtc; + struct drm_crtc *crtc; + int ret; + + exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL); + if (!exynos_crtc) + return ERR_PTR(-ENOMEM); + + exynos_crtc->type = type; + exynos_crtc->ops = ops; + exynos_crtc->ctx = ctx; + + crtc = &exynos_crtc->base; + + ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL, + &exynos_crtc_funcs, NULL); + if (ret < 0) + goto err_crtc; + + drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs); + + return exynos_crtc; + +err_crtc: + plane->funcs->destroy(plane); + kfree(exynos_crtc); + return ERR_PTR(ret); +} + +struct exynos_drm_crtc *exynos_drm_crtc_get_by_type(struct drm_device *drm_dev, + enum exynos_drm_output_type out_type) +{ + struct drm_crtc *crtc; + + drm_for_each_crtc(crtc, drm_dev) + if (to_exynos_crtc(crtc)->type == out_type) + return to_exynos_crtc(crtc); + + return ERR_PTR(-ENODEV); +} + +int exynos_drm_set_possible_crtcs(struct drm_encoder *encoder, + enum exynos_drm_output_type out_type) +{ + struct exynos_drm_crtc *crtc = exynos_drm_crtc_get_by_type(encoder->dev, + out_type); + + if (IS_ERR(crtc)) + return PTR_ERR(crtc); + + encoder->possible_crtcs = drm_crtc_mask(&crtc->base); + + return 0; +} + +void exynos_drm_crtc_te_handler(struct drm_crtc *crtc) +{ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + + if (exynos_crtc->ops->te_handler) + exynos_crtc->ops->te_handler(exynos_crtc); +} -- cgit v1.2.3