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 2463498e30SGustavo Padovan static void exynos_drm_crtc_enable(struct drm_crtc *crtc) 251c248b7dSInki Dae { 26d2716c89SJoonyoung Shim struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 271c248b7dSInki Dae 283cecda03SGustavo Padovan if (exynos_crtc->ops->enable) 293cecda03SGustavo Padovan exynos_crtc->ops->enable(exynos_crtc); 30080be03dSSean Paul 31d6948b2fSAndrzej Hajda drm_crtc_vblank_on(crtc); 321c248b7dSInki Dae } 331c248b7dSInki Dae 343fc4867cSGustavo Padovan static void exynos_drm_crtc_disable(struct drm_crtc *crtc) 353fc4867cSGustavo Padovan { 3663498e30SGustavo Padovan struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 373fc4867cSGustavo Padovan 3863498e30SGustavo Padovan drm_crtc_vblank_off(crtc); 3963498e30SGustavo Padovan 403cecda03SGustavo Padovan if (exynos_crtc->ops->disable) 413cecda03SGustavo Padovan exynos_crtc->ops->disable(exynos_crtc); 4241cbf0fdSInki Dae 4341cbf0fdSInki Dae if (crtc->state->event && !crtc->state->active) { 4441cbf0fdSInki Dae spin_lock_irq(&crtc->dev->event_lock); 4541cbf0fdSInki Dae drm_crtc_send_vblank_event(crtc, crtc->state->event); 4641cbf0fdSInki Dae spin_unlock_irq(&crtc->dev->event_lock); 4741cbf0fdSInki Dae 4841cbf0fdSInki Dae crtc->state->event = NULL; 4941cbf0fdSInki Dae } 503fc4867cSGustavo Padovan } 513fc4867cSGustavo Padovan 52199329cbSGustavo Padovan static void 53199329cbSGustavo Padovan exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) 541c248b7dSInki Dae { 554070d212SJoonyoung Shim struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 561c248b7dSInki Dae 57199329cbSGustavo Padovan if (exynos_crtc->ops->commit) 58199329cbSGustavo Padovan exynos_crtc->ops->commit(exynos_crtc); 591c248b7dSInki Dae } 601c248b7dSInki Dae 615625b341SAndrzej Hajda static int exynos_crtc_atomic_check(struct drm_crtc *crtc, 625625b341SAndrzej Hajda struct drm_crtc_state *state) 635625b341SAndrzej Hajda { 645625b341SAndrzej Hajda struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 655625b341SAndrzej Hajda 66c4e07407SAndrzej Hajda if (!state->enable) 67c4e07407SAndrzej Hajda return 0; 68c4e07407SAndrzej Hajda 695625b341SAndrzej Hajda if (exynos_crtc->ops->atomic_check) 705625b341SAndrzej Hajda return exynos_crtc->ops->atomic_check(exynos_crtc, state); 715625b341SAndrzej Hajda 725625b341SAndrzej Hajda return 0; 735625b341SAndrzej Hajda } 745625b341SAndrzej Hajda 75613d2b27SMaarten Lankhorst static void exynos_crtc_atomic_begin(struct drm_crtc *crtc, 76613d2b27SMaarten Lankhorst struct drm_crtc_state *old_crtc_state) 779d5ab6a0SGustavo Padovan { 789d5ab6a0SGustavo Padovan struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 799d5ab6a0SGustavo Padovan 80d9220d47SGustavo Padovan if (exynos_crtc->ops->atomic_begin) 81d29c2c14SMarek Szyprowski exynos_crtc->ops->atomic_begin(exynos_crtc); 829d5ab6a0SGustavo Padovan } 839d5ab6a0SGustavo Padovan 84613d2b27SMaarten Lankhorst static void exynos_crtc_atomic_flush(struct drm_crtc *crtc, 85613d2b27SMaarten Lankhorst struct drm_crtc_state *old_crtc_state) 869d5ab6a0SGustavo Padovan { 87d9220d47SGustavo Padovan struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 88d9220d47SGustavo Padovan 89d9220d47SGustavo Padovan if (exynos_crtc->ops->atomic_flush) 90d29c2c14SMarek Szyprowski exynos_crtc->ops->atomic_flush(exynos_crtc); 919d5ab6a0SGustavo Padovan } 929d5ab6a0SGustavo Padovan 93800ba2b5SVille Syrjälä static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { 9463498e30SGustavo Padovan .enable = exynos_drm_crtc_enable, 953fc4867cSGustavo Padovan .disable = exynos_drm_crtc_disable, 96199329cbSGustavo Padovan .mode_set_nofb = exynos_drm_crtc_mode_set_nofb, 975625b341SAndrzej Hajda .atomic_check = exynos_crtc_atomic_check, 989d5ab6a0SGustavo Padovan .atomic_begin = exynos_crtc_atomic_begin, 999d5ab6a0SGustavo Padovan .atomic_flush = exynos_crtc_atomic_flush, 1001c248b7dSInki Dae }; 1011c248b7dSInki Dae 102a392276dSAndrzej Hajda void exynos_crtc_handle_event(struct exynos_drm_crtc *exynos_crtc) 103a392276dSAndrzej Hajda { 104a392276dSAndrzej Hajda struct drm_crtc *crtc = &exynos_crtc->base; 105a392276dSAndrzej Hajda struct drm_pending_vblank_event *event = crtc->state->event; 106a392276dSAndrzej Hajda unsigned long flags; 107a392276dSAndrzej Hajda 108a392276dSAndrzej Hajda if (event) { 109a392276dSAndrzej Hajda crtc->state->event = NULL; 110a392276dSAndrzej Hajda spin_lock_irqsave(&crtc->dev->event_lock, flags); 111a392276dSAndrzej Hajda if (drm_crtc_vblank_get(crtc) == 0) 112a392276dSAndrzej Hajda drm_crtc_arm_vblank_event(crtc, event); 113a392276dSAndrzej Hajda else 114a392276dSAndrzej Hajda drm_crtc_send_vblank_event(crtc, event); 115a392276dSAndrzej Hajda spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 116a392276dSAndrzej Hajda } 117a392276dSAndrzej Hajda 118a392276dSAndrzej Hajda } 119a392276dSAndrzej Hajda 1201c248b7dSInki Dae static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) 1211c248b7dSInki Dae { 1221c248b7dSInki Dae struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 1231c248b7dSInki Dae 1241c248b7dSInki Dae drm_crtc_cleanup(crtc); 1251c248b7dSInki Dae kfree(exynos_crtc); 1261c248b7dSInki Dae } 1271c248b7dSInki Dae 128800ba2b5SVille Syrjälä static const struct drm_crtc_funcs exynos_crtc_funcs = { 12947a7deffSGustavo Padovan .set_config = drm_atomic_helper_set_config, 1309d5ab6a0SGustavo Padovan .page_flip = drm_atomic_helper_page_flip, 1311c248b7dSInki Dae .destroy = exynos_drm_crtc_destroy, 1324ea9526bSGustavo Padovan .reset = drm_atomic_helper_crtc_reset, 1334ea9526bSGustavo Padovan .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 1344ea9526bSGustavo Padovan .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 1351c248b7dSInki Dae }; 1361c248b7dSInki Dae 13793bca243SGustavo Padovan struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, 1387ee14cdcSGustavo Padovan struct drm_plane *plane, 13993bca243SGustavo Padovan int pipe, 14093bca243SGustavo Padovan enum exynos_drm_output_type type, 141f3aaf762SKrzysztof Kozlowski const struct exynos_drm_crtc_ops *ops, 14293bca243SGustavo Padovan void *ctx) 1431c248b7dSInki Dae { 1441c248b7dSInki Dae struct exynos_drm_crtc *exynos_crtc; 1451c248b7dSInki Dae struct drm_crtc *crtc; 14672ed6ccdSAndrzej Hajda int ret; 1471c248b7dSInki Dae 1481c248b7dSInki Dae exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL); 14938bb5253SSachin Kamat if (!exynos_crtc) 15093bca243SGustavo Padovan return ERR_PTR(-ENOMEM); 1511c248b7dSInki Dae 152e09f2b0dSGustavo Padovan exynos_crtc->pipe = pipe; 1535d1741adSGustavo Padovan exynos_crtc->type = type; 15493bca243SGustavo Padovan exynos_crtc->ops = ops; 15593bca243SGustavo Padovan exynos_crtc->ctx = ctx; 156b5d2eb3bSJoonyoung Shim 157357193cdSGustavo Padovan crtc = &exynos_crtc->base; 1581c248b7dSInki Dae 159eb88e422SGustavo Padovan ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL, 160f9882876SVille Syrjälä &exynos_crtc_funcs, NULL); 16172ed6ccdSAndrzej Hajda if (ret < 0) 16272ed6ccdSAndrzej Hajda goto err_crtc; 16372ed6ccdSAndrzej Hajda 1641c248b7dSInki Dae drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs); 1651c248b7dSInki Dae 16693bca243SGustavo Padovan return exynos_crtc; 16772ed6ccdSAndrzej Hajda 16872ed6ccdSAndrzej Hajda err_crtc: 16972ed6ccdSAndrzej Hajda plane->funcs->destroy(plane); 17072ed6ccdSAndrzej Hajda kfree(exynos_crtc); 17193bca243SGustavo Padovan return ERR_PTR(ret); 1721c248b7dSInki Dae } 1731c248b7dSInki Dae 17488e72717SThierry Reding int exynos_drm_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe) 1751c248b7dSInki Dae { 17627019328SAndrzej Hajda struct exynos_drm_crtc *exynos_crtc = exynos_drm_crtc_from_pipe(dev, 17727019328SAndrzej Hajda pipe); 1781c248b7dSInki Dae 17993bca243SGustavo Padovan if (exynos_crtc->ops->enable_vblank) 18008dd2009SGustavo Padovan return exynos_crtc->ops->enable_vblank(exynos_crtc); 1811c248b7dSInki Dae 1821c248b7dSInki Dae return 0; 1831c248b7dSInki Dae } 1841c248b7dSInki Dae 18588e72717SThierry Reding void exynos_drm_crtc_disable_vblank(struct drm_device *dev, unsigned int pipe) 1861c248b7dSInki Dae { 18727019328SAndrzej Hajda struct exynos_drm_crtc *exynos_crtc = exynos_drm_crtc_from_pipe(dev, 18827019328SAndrzej Hajda pipe); 1891c248b7dSInki Dae 19093bca243SGustavo Padovan if (exynos_crtc->ops->disable_vblank) 19193bca243SGustavo Padovan exynos_crtc->ops->disable_vblank(exynos_crtc); 1921c248b7dSInki Dae } 193663d8766SRahul Sharma 194f37cd5e8SInki Dae int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, 195cf67cc9aSGustavo Padovan enum exynos_drm_output_type out_type) 196f37cd5e8SInki Dae { 197f37cd5e8SInki Dae struct drm_crtc *crtc; 198f37cd5e8SInki Dae 199f37cd5e8SInki Dae list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) { 200f37cd5e8SInki Dae struct exynos_drm_crtc *exynos_crtc; 201f37cd5e8SInki Dae 202f37cd5e8SInki Dae exynos_crtc = to_exynos_crtc(crtc); 2035d1741adSGustavo Padovan if (exynos_crtc->type == out_type) 2048a326eddSGustavo Padovan return exynos_crtc->pipe; 205f37cd5e8SInki Dae } 206f37cd5e8SInki Dae 207f37cd5e8SInki Dae return -EPERM; 208f37cd5e8SInki Dae } 2095595d4d8SYoungJun Cho 2105595d4d8SYoungJun Cho void exynos_drm_crtc_te_handler(struct drm_crtc *crtc) 2115595d4d8SYoungJun Cho { 21293bca243SGustavo Padovan struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 2135595d4d8SYoungJun Cho 21493bca243SGustavo Padovan if (exynos_crtc->ops->te_handler) 21593bca243SGustavo Padovan exynos_crtc->ops->te_handler(exynos_crtc); 2165595d4d8SYoungJun Cho } 217