11c248b7dSInki Dae /* exynos_drm_crtc.c 21c248b7dSInki Dae * 31c248b7dSInki Dae * Copyright (c) 2011 Samsung Electronics Co., Ltd. 41c248b7dSInki Dae * Authors: 51c248b7dSInki Dae * Inki Dae <inki.dae@samsung.com> 61c248b7dSInki Dae * Joonyoung Shim <jy0922.shim@samsung.com> 71c248b7dSInki Dae * Seung-Woo Kim <sw0312.kim@samsung.com> 81c248b7dSInki Dae * 9d81aecb5SInki Dae * This program is free software; you can redistribute it and/or modify it 10d81aecb5SInki Dae * under the terms of the GNU General Public License as published by the 11d81aecb5SInki Dae * Free Software Foundation; either version 2 of the License, or (at your 12d81aecb5SInki Dae * option) any later version. 131c248b7dSInki Dae */ 141c248b7dSInki Dae 15760285e7SDavid Howells #include <drm/drmP.h> 16760285e7SDavid Howells #include <drm/drm_crtc_helper.h> 174ea9526bSGustavo Padovan #include <drm/drm_atomic.h> 184ea9526bSGustavo Padovan #include <drm/drm_atomic_helper.h> 191ca582f1SAndrzej Hajda #include <drm/drm_encoder.h> 201c248b7dSInki Dae 21e30655d0SMark Brown #include "exynos_drm_crtc.h" 221c248b7dSInki Dae #include "exynos_drm_drv.h" 23b5d2eb3bSJoonyoung Shim #include "exynos_drm_plane.h" 241c248b7dSInki Dae 250b20a0f8SLaurent Pinchart static void exynos_drm_crtc_atomic_enable(struct drm_crtc *crtc, 260b20a0f8SLaurent Pinchart struct drm_crtc_state *old_state) 271c248b7dSInki Dae { 28d2716c89SJoonyoung Shim struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 291c248b7dSInki Dae 303cecda03SGustavo Padovan if (exynos_crtc->ops->enable) 313cecda03SGustavo Padovan exynos_crtc->ops->enable(exynos_crtc); 32080be03dSSean Paul 33d6948b2fSAndrzej Hajda drm_crtc_vblank_on(crtc); 341c248b7dSInki Dae } 351c248b7dSInki Dae 3664581714SLaurent Pinchart static void exynos_drm_crtc_atomic_disable(struct drm_crtc *crtc, 3764581714SLaurent Pinchart struct drm_crtc_state *old_state) 383fc4867cSGustavo Padovan { 3963498e30SGustavo Padovan struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 403fc4867cSGustavo Padovan 4163498e30SGustavo Padovan drm_crtc_vblank_off(crtc); 4263498e30SGustavo Padovan 433cecda03SGustavo Padovan if (exynos_crtc->ops->disable) 443cecda03SGustavo Padovan exynos_crtc->ops->disable(exynos_crtc); 4541cbf0fdSInki Dae 4641cbf0fdSInki Dae if (crtc->state->event && !crtc->state->active) { 4741cbf0fdSInki Dae spin_lock_irq(&crtc->dev->event_lock); 4841cbf0fdSInki Dae drm_crtc_send_vblank_event(crtc, crtc->state->event); 4941cbf0fdSInki Dae spin_unlock_irq(&crtc->dev->event_lock); 5041cbf0fdSInki Dae 5141cbf0fdSInki Dae crtc->state->event = NULL; 5241cbf0fdSInki Dae } 533fc4867cSGustavo Padovan } 543fc4867cSGustavo Padovan 555625b341SAndrzej Hajda static int exynos_crtc_atomic_check(struct drm_crtc *crtc, 565625b341SAndrzej Hajda struct drm_crtc_state *state) 575625b341SAndrzej Hajda { 585625b341SAndrzej Hajda struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 595625b341SAndrzej Hajda 60c4e07407SAndrzej Hajda if (!state->enable) 61c4e07407SAndrzej Hajda return 0; 62c4e07407SAndrzej Hajda 635625b341SAndrzej Hajda if (exynos_crtc->ops->atomic_check) 645625b341SAndrzej Hajda return exynos_crtc->ops->atomic_check(exynos_crtc, state); 655625b341SAndrzej Hajda 665625b341SAndrzej Hajda return 0; 675625b341SAndrzej Hajda } 685625b341SAndrzej Hajda 69613d2b27SMaarten Lankhorst static void exynos_crtc_atomic_begin(struct drm_crtc *crtc, 70613d2b27SMaarten Lankhorst struct drm_crtc_state *old_crtc_state) 719d5ab6a0SGustavo Padovan { 729d5ab6a0SGustavo Padovan struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 739d5ab6a0SGustavo Padovan 74d9220d47SGustavo Padovan if (exynos_crtc->ops->atomic_begin) 75d29c2c14SMarek Szyprowski exynos_crtc->ops->atomic_begin(exynos_crtc); 769d5ab6a0SGustavo Padovan } 779d5ab6a0SGustavo Padovan 78613d2b27SMaarten Lankhorst static void exynos_crtc_atomic_flush(struct drm_crtc *crtc, 79613d2b27SMaarten Lankhorst struct drm_crtc_state *old_crtc_state) 809d5ab6a0SGustavo Padovan { 81d9220d47SGustavo Padovan struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 82d9220d47SGustavo Padovan 83d9220d47SGustavo Padovan if (exynos_crtc->ops->atomic_flush) 84d29c2c14SMarek Szyprowski exynos_crtc->ops->atomic_flush(exynos_crtc); 859d5ab6a0SGustavo Padovan } 869d5ab6a0SGustavo Padovan 87c3653fedSAndrzej Hajda static enum drm_mode_status exynos_crtc_mode_valid(struct drm_crtc *crtc, 88c3653fedSAndrzej Hajda const struct drm_display_mode *mode) 89c3653fedSAndrzej Hajda { 90c3653fedSAndrzej Hajda struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 91c3653fedSAndrzej Hajda 92c3653fedSAndrzej Hajda if (exynos_crtc->ops->mode_valid) 93c3653fedSAndrzej Hajda return exynos_crtc->ops->mode_valid(exynos_crtc, mode); 94c3653fedSAndrzej Hajda 95c3653fedSAndrzej Hajda return MODE_OK; 96c3653fedSAndrzej Hajda } 97c3653fedSAndrzej Hajda 982466db97SAndrzej Hajda static bool exynos_crtc_mode_fixup(struct drm_crtc *crtc, 992466db97SAndrzej Hajda const struct drm_display_mode *mode, 1002466db97SAndrzej Hajda struct drm_display_mode *adjusted_mode) 1012466db97SAndrzej Hajda { 1022466db97SAndrzej Hajda struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 1032466db97SAndrzej Hajda 1042466db97SAndrzej Hajda if (exynos_crtc->ops->mode_fixup) 1052466db97SAndrzej Hajda return exynos_crtc->ops->mode_fixup(exynos_crtc, mode, 1062466db97SAndrzej Hajda adjusted_mode); 1072466db97SAndrzej Hajda 1082466db97SAndrzej Hajda return true; 1092466db97SAndrzej Hajda } 1102466db97SAndrzej Hajda 1112466db97SAndrzej Hajda 112800ba2b5SVille Syrjälä static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { 113c3653fedSAndrzej Hajda .mode_valid = exynos_crtc_mode_valid, 1142466db97SAndrzej Hajda .mode_fixup = exynos_crtc_mode_fixup, 1155625b341SAndrzej Hajda .atomic_check = exynos_crtc_atomic_check, 1169d5ab6a0SGustavo Padovan .atomic_begin = exynos_crtc_atomic_begin, 1179d5ab6a0SGustavo Padovan .atomic_flush = exynos_crtc_atomic_flush, 1180b20a0f8SLaurent Pinchart .atomic_enable = exynos_drm_crtc_atomic_enable, 11964581714SLaurent Pinchart .atomic_disable = exynos_drm_crtc_atomic_disable, 1201c248b7dSInki Dae }; 1211c248b7dSInki Dae 122a392276dSAndrzej Hajda void exynos_crtc_handle_event(struct exynos_drm_crtc *exynos_crtc) 123a392276dSAndrzej Hajda { 124a392276dSAndrzej Hajda struct drm_crtc *crtc = &exynos_crtc->base; 125a392276dSAndrzej Hajda struct drm_pending_vblank_event *event = crtc->state->event; 126a392276dSAndrzej Hajda unsigned long flags; 127a392276dSAndrzej Hajda 12873b7b44fSAndrzej Hajda if (!event) 12973b7b44fSAndrzej Hajda return; 130a392276dSAndrzej Hajda crtc->state->event = NULL; 131a392276dSAndrzej Hajda 13273b7b44fSAndrzej Hajda WARN_ON(drm_crtc_vblank_get(crtc) != 0); 13373b7b44fSAndrzej Hajda 13473b7b44fSAndrzej Hajda spin_lock_irqsave(&crtc->dev->event_lock, flags); 13573b7b44fSAndrzej Hajda drm_crtc_arm_vblank_event(crtc, event); 13673b7b44fSAndrzej Hajda spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 137a392276dSAndrzej Hajda } 138a392276dSAndrzej Hajda 1391c248b7dSInki Dae static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) 1401c248b7dSInki Dae { 1411c248b7dSInki Dae struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 1421c248b7dSInki Dae 1431c248b7dSInki Dae drm_crtc_cleanup(crtc); 1441c248b7dSInki Dae kfree(exynos_crtc); 1451c248b7dSInki Dae } 1461c248b7dSInki Dae 14764b0e1d6SShawn Guo static int exynos_drm_crtc_enable_vblank(struct drm_crtc *crtc) 14864b0e1d6SShawn Guo { 14964b0e1d6SShawn Guo struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 15064b0e1d6SShawn Guo 15164b0e1d6SShawn Guo if (exynos_crtc->ops->enable_vblank) 15264b0e1d6SShawn Guo return exynos_crtc->ops->enable_vblank(exynos_crtc); 15364b0e1d6SShawn Guo 15464b0e1d6SShawn Guo return 0; 15564b0e1d6SShawn Guo } 15664b0e1d6SShawn Guo 15764b0e1d6SShawn Guo static void exynos_drm_crtc_disable_vblank(struct drm_crtc *crtc) 15864b0e1d6SShawn Guo { 15964b0e1d6SShawn Guo struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 16064b0e1d6SShawn Guo 16164b0e1d6SShawn Guo if (exynos_crtc->ops->disable_vblank) 16264b0e1d6SShawn Guo exynos_crtc->ops->disable_vblank(exynos_crtc); 16364b0e1d6SShawn Guo } 16464b0e1d6SShawn Guo 1650586febaSAndrzej Hajda static u32 exynos_drm_crtc_get_vblank_counter(struct drm_crtc *crtc) 1660586febaSAndrzej Hajda { 1670586febaSAndrzej Hajda struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 1680586febaSAndrzej Hajda 1690586febaSAndrzej Hajda if (exynos_crtc->ops->get_vblank_counter) 1700586febaSAndrzej Hajda return exynos_crtc->ops->get_vblank_counter(exynos_crtc); 1710586febaSAndrzej Hajda 1720586febaSAndrzej Hajda return 0; 1730586febaSAndrzej Hajda } 1740586febaSAndrzej Hajda 175800ba2b5SVille Syrjälä static const struct drm_crtc_funcs exynos_crtc_funcs = { 17647a7deffSGustavo Padovan .set_config = drm_atomic_helper_set_config, 1779d5ab6a0SGustavo Padovan .page_flip = drm_atomic_helper_page_flip, 1781c248b7dSInki Dae .destroy = exynos_drm_crtc_destroy, 1794ea9526bSGustavo Padovan .reset = drm_atomic_helper_crtc_reset, 1804ea9526bSGustavo Padovan .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 1814ea9526bSGustavo Padovan .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 18264b0e1d6SShawn Guo .enable_vblank = exynos_drm_crtc_enable_vblank, 18364b0e1d6SShawn Guo .disable_vblank = exynos_drm_crtc_disable_vblank, 1840586febaSAndrzej Hajda .get_vblank_counter = exynos_drm_crtc_get_vblank_counter, 1851c248b7dSInki Dae }; 1861c248b7dSInki Dae 18793bca243SGustavo Padovan struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, 1887ee14cdcSGustavo Padovan struct drm_plane *plane, 18993bca243SGustavo Padovan enum exynos_drm_output_type type, 190f3aaf762SKrzysztof Kozlowski const struct exynos_drm_crtc_ops *ops, 19193bca243SGustavo Padovan void *ctx) 1921c248b7dSInki Dae { 1931c248b7dSInki Dae struct exynos_drm_crtc *exynos_crtc; 1941c248b7dSInki Dae struct drm_crtc *crtc; 19572ed6ccdSAndrzej Hajda int ret; 1961c248b7dSInki Dae 1971c248b7dSInki Dae exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL); 19838bb5253SSachin Kamat if (!exynos_crtc) 19993bca243SGustavo Padovan return ERR_PTR(-ENOMEM); 2001c248b7dSInki Dae 2015d1741adSGustavo Padovan exynos_crtc->type = type; 20293bca243SGustavo Padovan exynos_crtc->ops = ops; 20393bca243SGustavo Padovan exynos_crtc->ctx = ctx; 204b5d2eb3bSJoonyoung Shim 205357193cdSGustavo Padovan crtc = &exynos_crtc->base; 2061c248b7dSInki Dae 207eb88e422SGustavo Padovan ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL, 208f9882876SVille Syrjälä &exynos_crtc_funcs, NULL); 20972ed6ccdSAndrzej Hajda if (ret < 0) 21072ed6ccdSAndrzej Hajda goto err_crtc; 21172ed6ccdSAndrzej Hajda 2121c248b7dSInki Dae drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs); 2131c248b7dSInki Dae 21493bca243SGustavo Padovan return exynos_crtc; 21572ed6ccdSAndrzej Hajda 21672ed6ccdSAndrzej Hajda err_crtc: 21772ed6ccdSAndrzej Hajda plane->funcs->destroy(plane); 21872ed6ccdSAndrzej Hajda kfree(exynos_crtc); 21993bca243SGustavo Padovan return ERR_PTR(ret); 2201c248b7dSInki Dae } 2211c248b7dSInki Dae 2221ca582f1SAndrzej Hajda struct exynos_drm_crtc *exynos_drm_crtc_get_by_type(struct drm_device *drm_dev, 223cf67cc9aSGustavo Padovan enum exynos_drm_output_type out_type) 224f37cd5e8SInki Dae { 225f37cd5e8SInki Dae struct drm_crtc *crtc; 226f37cd5e8SInki Dae 227d644951cSAndrzej Hajda drm_for_each_crtc(crtc, drm_dev) 228d644951cSAndrzej Hajda if (to_exynos_crtc(crtc)->type == out_type) 2291ca582f1SAndrzej Hajda return to_exynos_crtc(crtc); 230f37cd5e8SInki Dae 231e9497dc2SMarek Szyprowski return ERR_PTR(-ENODEV); 2321ca582f1SAndrzej Hajda } 2331ca582f1SAndrzej Hajda 2341ca582f1SAndrzej Hajda int exynos_drm_set_possible_crtcs(struct drm_encoder *encoder, 2351ca582f1SAndrzej Hajda enum exynos_drm_output_type out_type) 2361ca582f1SAndrzej Hajda { 2371ca582f1SAndrzej Hajda struct exynos_drm_crtc *crtc = exynos_drm_crtc_get_by_type(encoder->dev, 2381ca582f1SAndrzej Hajda out_type); 2391ca582f1SAndrzej Hajda 2401ca582f1SAndrzej Hajda if (IS_ERR(crtc)) 2411ca582f1SAndrzej Hajda return PTR_ERR(crtc); 2421ca582f1SAndrzej Hajda 2431ca582f1SAndrzej Hajda encoder->possible_crtcs = drm_crtc_mask(&crtc->base); 2441ca582f1SAndrzej Hajda 2451ca582f1SAndrzej Hajda return 0; 246f37cd5e8SInki Dae } 2475595d4d8SYoungJun Cho 2485595d4d8SYoungJun Cho void exynos_drm_crtc_te_handler(struct drm_crtc *crtc) 2495595d4d8SYoungJun Cho { 25093bca243SGustavo Padovan struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 2515595d4d8SYoungJun Cho 25293bca243SGustavo Padovan if (exynos_crtc->ops->te_handler) 25393bca243SGustavo Padovan exynos_crtc->ops->te_handler(exynos_crtc); 2545595d4d8SYoungJun Cho } 255