12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21c248b7dSInki Dae /* exynos_drm_crtc.c
31c248b7dSInki Dae *
41c248b7dSInki Dae * Copyright (c) 2011 Samsung Electronics Co., Ltd.
51c248b7dSInki Dae * Authors:
61c248b7dSInki Dae * Inki Dae <inki.dae@samsung.com>
71c248b7dSInki Dae * Joonyoung Shim <jy0922.shim@samsung.com>
81c248b7dSInki Dae * Seung-Woo Kim <sw0312.kim@samsung.com>
91c248b7dSInki Dae */
101c248b7dSInki Dae
114ea9526bSGustavo Padovan #include <drm/drm_atomic.h>
124ea9526bSGustavo Padovan #include <drm/drm_atomic_helper.h>
131ca582f1SAndrzej Hajda #include <drm/drm_encoder.h>
14fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h>
152bda34d7SSam Ravnborg #include <drm/drm_vblank.h>
161c248b7dSInki Dae
17e30655d0SMark Brown #include "exynos_drm_crtc.h"
181c248b7dSInki Dae #include "exynos_drm_drv.h"
19b5d2eb3bSJoonyoung Shim #include "exynos_drm_plane.h"
201c248b7dSInki Dae
exynos_drm_crtc_atomic_enable(struct drm_crtc * crtc,struct drm_atomic_state * state)210b20a0f8SLaurent Pinchart static void exynos_drm_crtc_atomic_enable(struct drm_crtc *crtc,
22351f950dSMaxime Ripard struct drm_atomic_state *state)
231c248b7dSInki Dae {
24d2716c89SJoonyoung Shim struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
251c248b7dSInki Dae
2611f95489SInki Dae if (exynos_crtc->ops->atomic_enable)
2711f95489SInki Dae exynos_crtc->ops->atomic_enable(exynos_crtc);
28080be03dSSean Paul
29d6948b2fSAndrzej Hajda drm_crtc_vblank_on(crtc);
301c248b7dSInki Dae }
311c248b7dSInki Dae
exynos_drm_crtc_atomic_disable(struct drm_crtc * crtc,struct drm_atomic_state * state)3264581714SLaurent Pinchart static void exynos_drm_crtc_atomic_disable(struct drm_crtc *crtc,
33351f950dSMaxime Ripard struct drm_atomic_state *state)
343fc4867cSGustavo Padovan {
3563498e30SGustavo Padovan struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
363fc4867cSGustavo Padovan
3763498e30SGustavo Padovan drm_crtc_vblank_off(crtc);
3863498e30SGustavo Padovan
3911f95489SInki Dae if (exynos_crtc->ops->atomic_disable)
4011f95489SInki Dae exynos_crtc->ops->atomic_disable(exynos_crtc);
4141cbf0fdSInki Dae
4241cbf0fdSInki Dae spin_lock_irq(&crtc->dev->event_lock);
43*2e63972aSTuo Li if (crtc->state->event && !crtc->state->active) {
4441cbf0fdSInki Dae drm_crtc_send_vblank_event(crtc, crtc->state->event);
4541cbf0fdSInki Dae crtc->state->event = NULL;
4641cbf0fdSInki Dae }
47*2e63972aSTuo Li spin_unlock_irq(&crtc->dev->event_lock);
483fc4867cSGustavo Padovan }
493fc4867cSGustavo Padovan
exynos_crtc_atomic_check(struct drm_crtc * crtc,struct drm_atomic_state * state)505625b341SAndrzej Hajda static int exynos_crtc_atomic_check(struct drm_crtc *crtc,
5129b77ad7SMaxime Ripard struct drm_atomic_state *state)
525625b341SAndrzej Hajda {
5329b77ad7SMaxime Ripard struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
5429b77ad7SMaxime Ripard crtc);
555625b341SAndrzej Hajda struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
565625b341SAndrzej Hajda
5729b77ad7SMaxime Ripard if (!crtc_state->enable)
58c4e07407SAndrzej Hajda return 0;
59c4e07407SAndrzej Hajda
605625b341SAndrzej Hajda if (exynos_crtc->ops->atomic_check)
6129b77ad7SMaxime Ripard return exynos_crtc->ops->atomic_check(exynos_crtc, crtc_state);
625625b341SAndrzej Hajda
635625b341SAndrzej Hajda return 0;
645625b341SAndrzej Hajda }
655625b341SAndrzej Hajda
exynos_crtc_atomic_begin(struct drm_crtc * crtc,struct drm_atomic_state * state)66613d2b27SMaarten Lankhorst static void exynos_crtc_atomic_begin(struct drm_crtc *crtc,
67f6ebe9f9SMaxime Ripard struct drm_atomic_state *state)
689d5ab6a0SGustavo Padovan {
699d5ab6a0SGustavo Padovan struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
709d5ab6a0SGustavo Padovan
71d9220d47SGustavo Padovan if (exynos_crtc->ops->atomic_begin)
72d29c2c14SMarek Szyprowski exynos_crtc->ops->atomic_begin(exynos_crtc);
739d5ab6a0SGustavo Padovan }
749d5ab6a0SGustavo Padovan
exynos_crtc_atomic_flush(struct drm_crtc * crtc,struct drm_atomic_state * state)75613d2b27SMaarten Lankhorst static void exynos_crtc_atomic_flush(struct drm_crtc *crtc,
76f6ebe9f9SMaxime Ripard struct drm_atomic_state *state)
779d5ab6a0SGustavo Padovan {
78d9220d47SGustavo Padovan struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
79d9220d47SGustavo Padovan
80d9220d47SGustavo Padovan if (exynos_crtc->ops->atomic_flush)
81d29c2c14SMarek Szyprowski exynos_crtc->ops->atomic_flush(exynos_crtc);
829d5ab6a0SGustavo Padovan }
839d5ab6a0SGustavo Padovan
exynos_crtc_mode_valid(struct drm_crtc * crtc,const struct drm_display_mode * mode)84c3653fedSAndrzej Hajda static enum drm_mode_status exynos_crtc_mode_valid(struct drm_crtc *crtc,
85c3653fedSAndrzej Hajda const struct drm_display_mode *mode)
86c3653fedSAndrzej Hajda {
87c3653fedSAndrzej Hajda struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
88c3653fedSAndrzej Hajda
89c3653fedSAndrzej Hajda if (exynos_crtc->ops->mode_valid)
90c3653fedSAndrzej Hajda return exynos_crtc->ops->mode_valid(exynos_crtc, mode);
91c3653fedSAndrzej Hajda
92c3653fedSAndrzej Hajda return MODE_OK;
93c3653fedSAndrzej Hajda }
94c3653fedSAndrzej Hajda
exynos_crtc_mode_fixup(struct drm_crtc * crtc,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)952466db97SAndrzej Hajda static bool exynos_crtc_mode_fixup(struct drm_crtc *crtc,
962466db97SAndrzej Hajda const struct drm_display_mode *mode,
972466db97SAndrzej Hajda struct drm_display_mode *adjusted_mode)
982466db97SAndrzej Hajda {
992466db97SAndrzej Hajda struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
1002466db97SAndrzej Hajda
1012466db97SAndrzej Hajda if (exynos_crtc->ops->mode_fixup)
1022466db97SAndrzej Hajda return exynos_crtc->ops->mode_fixup(exynos_crtc, mode,
1032466db97SAndrzej Hajda adjusted_mode);
1042466db97SAndrzej Hajda
1052466db97SAndrzej Hajda return true;
1062466db97SAndrzej Hajda }
1072466db97SAndrzej Hajda
1082466db97SAndrzej Hajda
109800ba2b5SVille Syrjälä static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
110c3653fedSAndrzej Hajda .mode_valid = exynos_crtc_mode_valid,
1112466db97SAndrzej Hajda .mode_fixup = exynos_crtc_mode_fixup,
1125625b341SAndrzej Hajda .atomic_check = exynos_crtc_atomic_check,
1139d5ab6a0SGustavo Padovan .atomic_begin = exynos_crtc_atomic_begin,
1149d5ab6a0SGustavo Padovan .atomic_flush = exynos_crtc_atomic_flush,
1150b20a0f8SLaurent Pinchart .atomic_enable = exynos_drm_crtc_atomic_enable,
11664581714SLaurent Pinchart .atomic_disable = exynos_drm_crtc_atomic_disable,
1171c248b7dSInki Dae };
1181c248b7dSInki Dae
exynos_crtc_handle_event(struct exynos_drm_crtc * exynos_crtc)119a392276dSAndrzej Hajda void exynos_crtc_handle_event(struct exynos_drm_crtc *exynos_crtc)
120a392276dSAndrzej Hajda {
121a392276dSAndrzej Hajda struct drm_crtc *crtc = &exynos_crtc->base;
122a392276dSAndrzej Hajda struct drm_pending_vblank_event *event = crtc->state->event;
123a392276dSAndrzej Hajda unsigned long flags;
124a392276dSAndrzej Hajda
12573b7b44fSAndrzej Hajda if (!event)
12673b7b44fSAndrzej Hajda return;
127a392276dSAndrzej Hajda crtc->state->event = NULL;
128a392276dSAndrzej Hajda
12973b7b44fSAndrzej Hajda WARN_ON(drm_crtc_vblank_get(crtc) != 0);
13073b7b44fSAndrzej Hajda
13173b7b44fSAndrzej Hajda spin_lock_irqsave(&crtc->dev->event_lock, flags);
13273b7b44fSAndrzej Hajda drm_crtc_arm_vblank_event(crtc, event);
13373b7b44fSAndrzej Hajda spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
134a392276dSAndrzej Hajda }
135a392276dSAndrzej Hajda
exynos_drm_crtc_destroy(struct drm_crtc * crtc)1361c248b7dSInki Dae static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
1371c248b7dSInki Dae {
1381c248b7dSInki Dae struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
1391c248b7dSInki Dae
1401c248b7dSInki Dae drm_crtc_cleanup(crtc);
1411c248b7dSInki Dae kfree(exynos_crtc);
1421c248b7dSInki Dae }
1431c248b7dSInki Dae
exynos_drm_crtc_enable_vblank(struct drm_crtc * crtc)14464b0e1d6SShawn Guo static int exynos_drm_crtc_enable_vblank(struct drm_crtc *crtc)
14564b0e1d6SShawn Guo {
14664b0e1d6SShawn Guo struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
14764b0e1d6SShawn Guo
14864b0e1d6SShawn Guo if (exynos_crtc->ops->enable_vblank)
14964b0e1d6SShawn Guo return exynos_crtc->ops->enable_vblank(exynos_crtc);
15064b0e1d6SShawn Guo
15164b0e1d6SShawn Guo return 0;
15264b0e1d6SShawn Guo }
15364b0e1d6SShawn Guo
exynos_drm_crtc_disable_vblank(struct drm_crtc * crtc)15464b0e1d6SShawn Guo static void exynos_drm_crtc_disable_vblank(struct drm_crtc *crtc)
15564b0e1d6SShawn Guo {
15664b0e1d6SShawn Guo struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
15764b0e1d6SShawn Guo
15864b0e1d6SShawn Guo if (exynos_crtc->ops->disable_vblank)
15964b0e1d6SShawn Guo exynos_crtc->ops->disable_vblank(exynos_crtc);
16064b0e1d6SShawn Guo }
16164b0e1d6SShawn Guo
162800ba2b5SVille Syrjälä static const struct drm_crtc_funcs exynos_crtc_funcs = {
16347a7deffSGustavo Padovan .set_config = drm_atomic_helper_set_config,
1649d5ab6a0SGustavo Padovan .page_flip = drm_atomic_helper_page_flip,
1651c248b7dSInki Dae .destroy = exynos_drm_crtc_destroy,
1664ea9526bSGustavo Padovan .reset = drm_atomic_helper_crtc_reset,
1674ea9526bSGustavo Padovan .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
1684ea9526bSGustavo Padovan .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
16964b0e1d6SShawn Guo .enable_vblank = exynos_drm_crtc_enable_vblank,
17064b0e1d6SShawn Guo .disable_vblank = exynos_drm_crtc_disable_vblank,
1711c248b7dSInki Dae };
1721c248b7dSInki Dae
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)17393bca243SGustavo Padovan struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
1747ee14cdcSGustavo Padovan struct drm_plane *plane,
17593bca243SGustavo Padovan enum exynos_drm_output_type type,
176f3aaf762SKrzysztof Kozlowski const struct exynos_drm_crtc_ops *ops,
17793bca243SGustavo Padovan void *ctx)
1781c248b7dSInki Dae {
1791c248b7dSInki Dae struct exynos_drm_crtc *exynos_crtc;
1801c248b7dSInki Dae struct drm_crtc *crtc;
18172ed6ccdSAndrzej Hajda int ret;
1821c248b7dSInki Dae
1831c248b7dSInki Dae exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
18438bb5253SSachin Kamat if (!exynos_crtc)
18593bca243SGustavo Padovan return ERR_PTR(-ENOMEM);
1861c248b7dSInki Dae
1875d1741adSGustavo Padovan exynos_crtc->type = type;
18893bca243SGustavo Padovan exynos_crtc->ops = ops;
18993bca243SGustavo Padovan exynos_crtc->ctx = ctx;
190b5d2eb3bSJoonyoung Shim
191357193cdSGustavo Padovan crtc = &exynos_crtc->base;
1921c248b7dSInki Dae
193eb88e422SGustavo Padovan ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL,
194f9882876SVille Syrjälä &exynos_crtc_funcs, NULL);
19572ed6ccdSAndrzej Hajda if (ret < 0)
19672ed6ccdSAndrzej Hajda goto err_crtc;
19772ed6ccdSAndrzej Hajda
1981c248b7dSInki Dae drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
1991c248b7dSInki Dae
20093bca243SGustavo Padovan return exynos_crtc;
20172ed6ccdSAndrzej Hajda
20272ed6ccdSAndrzej Hajda err_crtc:
20372ed6ccdSAndrzej Hajda plane->funcs->destroy(plane);
20472ed6ccdSAndrzej Hajda kfree(exynos_crtc);
20593bca243SGustavo Padovan return ERR_PTR(ret);
2061c248b7dSInki Dae }
2071c248b7dSInki Dae
exynos_drm_crtc_get_by_type(struct drm_device * drm_dev,enum exynos_drm_output_type out_type)2081ca582f1SAndrzej Hajda struct exynos_drm_crtc *exynos_drm_crtc_get_by_type(struct drm_device *drm_dev,
209cf67cc9aSGustavo Padovan enum exynos_drm_output_type out_type)
210f37cd5e8SInki Dae {
211f37cd5e8SInki Dae struct drm_crtc *crtc;
212f37cd5e8SInki Dae
213d644951cSAndrzej Hajda drm_for_each_crtc(crtc, drm_dev)
214d644951cSAndrzej Hajda if (to_exynos_crtc(crtc)->type == out_type)
2151ca582f1SAndrzej Hajda return to_exynos_crtc(crtc);
216f37cd5e8SInki Dae
217e9497dc2SMarek Szyprowski return ERR_PTR(-ENODEV);
2181ca582f1SAndrzej Hajda }
2191ca582f1SAndrzej Hajda
exynos_drm_set_possible_crtcs(struct drm_encoder * encoder,enum exynos_drm_output_type out_type)2201ca582f1SAndrzej Hajda int exynos_drm_set_possible_crtcs(struct drm_encoder *encoder,
2211ca582f1SAndrzej Hajda enum exynos_drm_output_type out_type)
2221ca582f1SAndrzej Hajda {
2231ca582f1SAndrzej Hajda struct exynos_drm_crtc *crtc = exynos_drm_crtc_get_by_type(encoder->dev,
2241ca582f1SAndrzej Hajda out_type);
2251ca582f1SAndrzej Hajda
2261ca582f1SAndrzej Hajda if (IS_ERR(crtc))
2271ca582f1SAndrzej Hajda return PTR_ERR(crtc);
2281ca582f1SAndrzej Hajda
2291ca582f1SAndrzej Hajda encoder->possible_crtcs = drm_crtc_mask(&crtc->base);
2301ca582f1SAndrzej Hajda
2311ca582f1SAndrzej Hajda return 0;
232f37cd5e8SInki Dae }
2335595d4d8SYoungJun Cho
exynos_drm_crtc_te_handler(struct drm_crtc * crtc)2345595d4d8SYoungJun Cho void exynos_drm_crtc_te_handler(struct drm_crtc *crtc)
2355595d4d8SYoungJun Cho {
23693bca243SGustavo Padovan struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
2375595d4d8SYoungJun Cho
23893bca243SGustavo Padovan if (exynos_crtc->ops->te_handler)
23993bca243SGustavo Padovan exynos_crtc->ops->te_handler(exynos_crtc);
2405595d4d8SYoungJun Cho }
241