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> 191c248b7dSInki Dae 20e30655d0SMark Brown #include "exynos_drm_crtc.h" 211c248b7dSInki Dae #include "exynos_drm_drv.h" 22b5d2eb3bSJoonyoung Shim #include "exynos_drm_plane.h" 231c248b7dSInki Dae 240b20a0f8SLaurent Pinchart static void exynos_drm_crtc_atomic_enable(struct drm_crtc *crtc, 250b20a0f8SLaurent Pinchart struct drm_crtc_state *old_state) 261c248b7dSInki Dae { 27d2716c89SJoonyoung Shim struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 281c248b7dSInki Dae 293cecda03SGustavo Padovan if (exynos_crtc->ops->enable) 303cecda03SGustavo Padovan exynos_crtc->ops->enable(exynos_crtc); 31080be03dSSean Paul 32d6948b2fSAndrzej Hajda drm_crtc_vblank_on(crtc); 331c248b7dSInki Dae } 341c248b7dSInki Dae 353fc4867cSGustavo Padovan static void exynos_drm_crtc_disable(struct drm_crtc *crtc) 363fc4867cSGustavo Padovan { 3763498e30SGustavo Padovan struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 383fc4867cSGustavo Padovan 3963498e30SGustavo Padovan drm_crtc_vblank_off(crtc); 4063498e30SGustavo Padovan 413cecda03SGustavo Padovan if (exynos_crtc->ops->disable) 423cecda03SGustavo Padovan exynos_crtc->ops->disable(exynos_crtc); 4341cbf0fdSInki Dae 4441cbf0fdSInki Dae if (crtc->state->event && !crtc->state->active) { 4541cbf0fdSInki Dae spin_lock_irq(&crtc->dev->event_lock); 4641cbf0fdSInki Dae drm_crtc_send_vblank_event(crtc, crtc->state->event); 4741cbf0fdSInki Dae spin_unlock_irq(&crtc->dev->event_lock); 4841cbf0fdSInki Dae 4941cbf0fdSInki Dae crtc->state->event = NULL; 5041cbf0fdSInki Dae } 513fc4867cSGustavo Padovan } 523fc4867cSGustavo Padovan 535625b341SAndrzej Hajda static int exynos_crtc_atomic_check(struct drm_crtc *crtc, 545625b341SAndrzej Hajda struct drm_crtc_state *state) 555625b341SAndrzej Hajda { 565625b341SAndrzej Hajda struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 575625b341SAndrzej Hajda 58c4e07407SAndrzej Hajda if (!state->enable) 59c4e07407SAndrzej Hajda return 0; 60c4e07407SAndrzej Hajda 615625b341SAndrzej Hajda if (exynos_crtc->ops->atomic_check) 625625b341SAndrzej Hajda return exynos_crtc->ops->atomic_check(exynos_crtc, state); 635625b341SAndrzej Hajda 645625b341SAndrzej Hajda return 0; 655625b341SAndrzej Hajda } 665625b341SAndrzej Hajda 67613d2b27SMaarten Lankhorst static void exynos_crtc_atomic_begin(struct drm_crtc *crtc, 68613d2b27SMaarten Lankhorst struct drm_crtc_state *old_crtc_state) 699d5ab6a0SGustavo Padovan { 709d5ab6a0SGustavo Padovan struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 719d5ab6a0SGustavo Padovan 72d9220d47SGustavo Padovan if (exynos_crtc->ops->atomic_begin) 73d29c2c14SMarek Szyprowski exynos_crtc->ops->atomic_begin(exynos_crtc); 749d5ab6a0SGustavo Padovan } 759d5ab6a0SGustavo Padovan 76613d2b27SMaarten Lankhorst static void exynos_crtc_atomic_flush(struct drm_crtc *crtc, 77613d2b27SMaarten Lankhorst struct drm_crtc_state *old_crtc_state) 789d5ab6a0SGustavo Padovan { 79d9220d47SGustavo Padovan struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 80d9220d47SGustavo Padovan 81d9220d47SGustavo Padovan if (exynos_crtc->ops->atomic_flush) 82d29c2c14SMarek Szyprowski exynos_crtc->ops->atomic_flush(exynos_crtc); 839d5ab6a0SGustavo Padovan } 849d5ab6a0SGustavo Padovan 85800ba2b5SVille Syrjälä static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { 863fc4867cSGustavo Padovan .disable = exynos_drm_crtc_disable, 875625b341SAndrzej Hajda .atomic_check = exynos_crtc_atomic_check, 889d5ab6a0SGustavo Padovan .atomic_begin = exynos_crtc_atomic_begin, 899d5ab6a0SGustavo Padovan .atomic_flush = exynos_crtc_atomic_flush, 900b20a0f8SLaurent Pinchart .atomic_enable = exynos_drm_crtc_atomic_enable, 911c248b7dSInki Dae }; 921c248b7dSInki Dae 93a392276dSAndrzej Hajda void exynos_crtc_handle_event(struct exynos_drm_crtc *exynos_crtc) 94a392276dSAndrzej Hajda { 95a392276dSAndrzej Hajda struct drm_crtc *crtc = &exynos_crtc->base; 96a392276dSAndrzej Hajda struct drm_pending_vblank_event *event = crtc->state->event; 97a392276dSAndrzej Hajda unsigned long flags; 98a392276dSAndrzej Hajda 9973b7b44fSAndrzej Hajda if (!event) 10073b7b44fSAndrzej Hajda return; 101a392276dSAndrzej Hajda crtc->state->event = NULL; 102a392276dSAndrzej Hajda 10373b7b44fSAndrzej Hajda WARN_ON(drm_crtc_vblank_get(crtc) != 0); 10473b7b44fSAndrzej Hajda 10573b7b44fSAndrzej Hajda spin_lock_irqsave(&crtc->dev->event_lock, flags); 10673b7b44fSAndrzej Hajda drm_crtc_arm_vblank_event(crtc, event); 10773b7b44fSAndrzej Hajda spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 108a392276dSAndrzej Hajda } 109a392276dSAndrzej Hajda 1101c248b7dSInki Dae static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) 1111c248b7dSInki Dae { 1121c248b7dSInki Dae struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 1131c248b7dSInki Dae 1141c248b7dSInki Dae drm_crtc_cleanup(crtc); 1151c248b7dSInki Dae kfree(exynos_crtc); 1161c248b7dSInki Dae } 1171c248b7dSInki Dae 11864b0e1d6SShawn Guo static int exynos_drm_crtc_enable_vblank(struct drm_crtc *crtc) 11964b0e1d6SShawn Guo { 12064b0e1d6SShawn Guo struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 12164b0e1d6SShawn Guo 12264b0e1d6SShawn Guo if (exynos_crtc->ops->enable_vblank) 12364b0e1d6SShawn Guo return exynos_crtc->ops->enable_vblank(exynos_crtc); 12464b0e1d6SShawn Guo 12564b0e1d6SShawn Guo return 0; 12664b0e1d6SShawn Guo } 12764b0e1d6SShawn Guo 12864b0e1d6SShawn Guo static void exynos_drm_crtc_disable_vblank(struct drm_crtc *crtc) 12964b0e1d6SShawn Guo { 13064b0e1d6SShawn Guo struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 13164b0e1d6SShawn Guo 13264b0e1d6SShawn Guo if (exynos_crtc->ops->disable_vblank) 13364b0e1d6SShawn Guo exynos_crtc->ops->disable_vblank(exynos_crtc); 13464b0e1d6SShawn Guo } 13564b0e1d6SShawn Guo 1360586febaSAndrzej Hajda static u32 exynos_drm_crtc_get_vblank_counter(struct drm_crtc *crtc) 1370586febaSAndrzej Hajda { 1380586febaSAndrzej Hajda struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 1390586febaSAndrzej Hajda 1400586febaSAndrzej Hajda if (exynos_crtc->ops->get_vblank_counter) 1410586febaSAndrzej Hajda return exynos_crtc->ops->get_vblank_counter(exynos_crtc); 1420586febaSAndrzej Hajda 1430586febaSAndrzej Hajda return 0; 1440586febaSAndrzej Hajda } 1450586febaSAndrzej Hajda 146800ba2b5SVille Syrjälä static const struct drm_crtc_funcs exynos_crtc_funcs = { 14747a7deffSGustavo Padovan .set_config = drm_atomic_helper_set_config, 1489d5ab6a0SGustavo Padovan .page_flip = drm_atomic_helper_page_flip, 1491c248b7dSInki Dae .destroy = exynos_drm_crtc_destroy, 1504ea9526bSGustavo Padovan .reset = drm_atomic_helper_crtc_reset, 1514ea9526bSGustavo Padovan .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 1524ea9526bSGustavo Padovan .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 15364b0e1d6SShawn Guo .enable_vblank = exynos_drm_crtc_enable_vblank, 15464b0e1d6SShawn Guo .disable_vblank = exynos_drm_crtc_disable_vblank, 1550586febaSAndrzej Hajda .get_vblank_counter = exynos_drm_crtc_get_vblank_counter, 1561c248b7dSInki Dae }; 1571c248b7dSInki Dae 15893bca243SGustavo Padovan struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, 1597ee14cdcSGustavo Padovan struct drm_plane *plane, 16093bca243SGustavo Padovan enum exynos_drm_output_type type, 161f3aaf762SKrzysztof Kozlowski const struct exynos_drm_crtc_ops *ops, 16293bca243SGustavo Padovan void *ctx) 1631c248b7dSInki Dae { 1641c248b7dSInki Dae struct exynos_drm_crtc *exynos_crtc; 1651c248b7dSInki Dae struct drm_crtc *crtc; 16672ed6ccdSAndrzej Hajda int ret; 1671c248b7dSInki Dae 1681c248b7dSInki Dae exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL); 16938bb5253SSachin Kamat if (!exynos_crtc) 17093bca243SGustavo Padovan return ERR_PTR(-ENOMEM); 1711c248b7dSInki Dae 1725d1741adSGustavo Padovan exynos_crtc->type = type; 17393bca243SGustavo Padovan exynos_crtc->ops = ops; 17493bca243SGustavo Padovan exynos_crtc->ctx = ctx; 175b5d2eb3bSJoonyoung Shim 176357193cdSGustavo Padovan crtc = &exynos_crtc->base; 1771c248b7dSInki Dae 178eb88e422SGustavo Padovan ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL, 179f9882876SVille Syrjälä &exynos_crtc_funcs, NULL); 18072ed6ccdSAndrzej Hajda if (ret < 0) 18172ed6ccdSAndrzej Hajda goto err_crtc; 18272ed6ccdSAndrzej Hajda 1831c248b7dSInki Dae drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs); 1841c248b7dSInki Dae 18593bca243SGustavo Padovan return exynos_crtc; 18672ed6ccdSAndrzej Hajda 18772ed6ccdSAndrzej Hajda err_crtc: 18872ed6ccdSAndrzej Hajda plane->funcs->destroy(plane); 18972ed6ccdSAndrzej Hajda kfree(exynos_crtc); 19093bca243SGustavo Padovan return ERR_PTR(ret); 1911c248b7dSInki Dae } 1921c248b7dSInki Dae 193f37cd5e8SInki Dae int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, 194cf67cc9aSGustavo Padovan enum exynos_drm_output_type out_type) 195f37cd5e8SInki Dae { 196f37cd5e8SInki Dae struct drm_crtc *crtc; 197f37cd5e8SInki Dae 198d644951cSAndrzej Hajda drm_for_each_crtc(crtc, drm_dev) 199d644951cSAndrzej Hajda if (to_exynos_crtc(crtc)->type == out_type) 200d644951cSAndrzej Hajda return drm_crtc_index(crtc); 201f37cd5e8SInki Dae 202f37cd5e8SInki Dae return -EPERM; 203f37cd5e8SInki Dae } 2045595d4d8SYoungJun Cho 2055595d4d8SYoungJun Cho void exynos_drm_crtc_te_handler(struct drm_crtc *crtc) 2065595d4d8SYoungJun Cho { 20793bca243SGustavo Padovan struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 2085595d4d8SYoungJun Cho 20993bca243SGustavo Padovan if (exynos_crtc->ops->te_handler) 21093bca243SGustavo Padovan exynos_crtc->ops->te_handler(exynos_crtc); 2115595d4d8SYoungJun Cho } 212