diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:49:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:49:45 +0000 |
commit | 2c3c1048746a4622d8c89a29670120dc8fab93c4 (patch) | |
tree | 848558de17fb3008cdf4d861b01ac7781903ce39 /drivers/gpu/drm/exynos/exynos_drm_crtc.c | |
parent | Initial commit. (diff) | |
download | linux-2c3c1048746a4622d8c89a29670120dc8fab93c4.tar.xz linux-2c3c1048746a4622d8c89a29670120dc8fab93c4.zip |
Adding upstream version 6.1.76.upstream/6.1.76
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_crtc.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_crtc.c | 240 |
1 files changed, 240 insertions, 0 deletions
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 <inki.dae@samsung.com> + * Joonyoung Shim <jy0922.shim@samsung.com> + * Seung-Woo Kim <sw0312.kim@samsung.com> + */ + +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_encoder.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> + +#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); +} |