blob: dd8e4549ea01986ff6e4b229a122365e37b66b56 [file] [log] [blame]
Inki Dae1c248b72011-10-04 19:19:01 +09001/* exynos_drm_crtc.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Authors:
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 * Seung-Woo Kim <sw0312.kim@samsung.com>
8 *
Inki Daed81aecb2012-12-18 02:30:17 +09009 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
Inki Dae1c248b72011-10-04 19:19:01 +090013 */
14
David Howells760285e2012-10-02 18:01:07 +010015#include <drm/drmP.h>
16#include <drm/drm_crtc_helper.h>
Gustavo Padovan4ea95262015-06-01 12:04:44 -030017#include <drm/drm_atomic.h>
18#include <drm/drm_atomic_helper.h>
Inki Dae1c248b72011-10-04 19:19:01 +090019
Mark Browne30655d2013-08-13 00:46:40 +010020#include "exynos_drm_crtc.h"
Inki Dae1c248b72011-10-04 19:19:01 +090021#include "exynos_drm_drv.h"
Inki Dae1c248b72011-10-04 19:19:01 +090022#include "exynos_drm_encoder.h"
Joonyoung Shimb5d2eb32012-06-27 14:27:04 +090023#include "exynos_drm_plane.h"
Inki Dae1c248b72011-10-04 19:19:01 +090024
Gustavo Padovan63498e32015-06-01 12:04:53 -030025static void exynos_drm_crtc_enable(struct drm_crtc *crtc)
Inki Dae1c248b72011-10-04 19:19:01 +090026{
Joonyoung Shimd2716c82011-11-04 17:04:45 +090027 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
Inki Dae1c248b72011-10-04 19:19:01 +090028
Gustavo Padovan63498e32015-06-01 12:04:53 -030029 if (exynos_crtc->enabled)
Inki Daeec05da92011-12-06 11:06:54 +090030 return;
Inki Dae20cd2642013-05-21 16:55:58 +090031
Gustavo Padovan93bca242015-01-18 18:16:23 +090032 if (exynos_crtc->ops->dpms)
Gustavo Padovan63498e32015-06-01 12:04:53 -030033 exynos_crtc->ops->dpms(exynos_crtc, DRM_MODE_DPMS_ON);
Sean Paul080be03d2014-02-19 21:02:55 +090034
Gustavo Padovan63498e32015-06-01 12:04:53 -030035 exynos_crtc->enabled = true;
Andrzej Hajdad6948b22014-10-10 14:31:55 +020036
Gustavo Padovan63498e32015-06-01 12:04:53 -030037 drm_crtc_vblank_on(crtc);
Inki Dae1c248b72011-10-04 19:19:01 +090038}
39
Gustavo Padovan3fc48672015-06-01 12:04:51 -030040static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
41{
Gustavo Padovan63498e32015-06-01 12:04:53 -030042 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
Gustavo Padovan3fc48672015-06-01 12:04:51 -030043 struct drm_plane *plane;
44 int ret;
45
Gustavo Padovan63498e32015-06-01 12:04:53 -030046 if (!exynos_crtc->enabled)
47 return;
48
49 /* wait for the completion of page flip. */
50 if (!wait_event_timeout(exynos_crtc->pending_flip_queue,
51 (exynos_crtc->event == NULL), HZ/20))
52 exynos_crtc->event = NULL;
53
54 drm_crtc_vblank_off(crtc);
55
56 if (exynos_crtc->ops->dpms)
57 exynos_crtc->ops->dpms(exynos_crtc, DRM_MODE_DPMS_OFF);
58
59 exynos_crtc->enabled = false;
Gustavo Padovan3fc48672015-06-01 12:04:51 -030060
61 drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) {
62 if (plane->crtc != crtc)
63 continue;
64
65 ret = plane->funcs->disable_plane(plane);
66 if (ret)
67 DRM_ERROR("Failed to disable plane %d\n", ret);
68 }
69}
70
Inki Dae1c248b72011-10-04 19:19:01 +090071static bool
72exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc,
Laurent Pincharte811f5a2012-07-17 17:56:50 +020073 const struct drm_display_mode *mode,
Inki Dae1c248b72011-10-04 19:19:01 +090074 struct drm_display_mode *adjusted_mode)
75{
Sean Paul4b405262014-01-30 16:19:19 -050076 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
Sean Paul4b405262014-01-30 16:19:19 -050077
Gustavo Padovan93bca242015-01-18 18:16:23 +090078 if (exynos_crtc->ops->mode_fixup)
79 return exynos_crtc->ops->mode_fixup(exynos_crtc, mode,
80 adjusted_mode);
Sean Paul4b405262014-01-30 16:19:19 -050081
Inki Dae1c248b72011-10-04 19:19:01 +090082 return true;
83}
84
Gustavo Padovan199329c2015-06-01 12:04:43 -030085static void
86exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
Inki Dae1c248b72011-10-04 19:19:01 +090087{
Joonyoung Shim4070d212012-06-27 14:27:05 +090088 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
Inki Dae1c248b72011-10-04 19:19:01 +090089
Gustavo Padovan199329c2015-06-01 12:04:43 -030090 if (exynos_crtc->ops->commit)
91 exynos_crtc->ops->commit(exynos_crtc);
Inki Dae1c248b72011-10-04 19:19:01 +090092}
93
Gustavo Padovan9d5ab6a2015-06-01 12:04:48 -030094static void exynos_crtc_atomic_begin(struct drm_crtc *crtc)
95{
96 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
97
98 if (crtc->state->event) {
99 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
100 exynos_crtc->event = crtc->state->event;
101 }
102}
103
104static void exynos_crtc_atomic_flush(struct drm_crtc *crtc)
105{
106}
107
Inki Dae1c248b72011-10-04 19:19:01 +0900108static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
Gustavo Padovan63498e32015-06-01 12:04:53 -0300109 .enable = exynos_drm_crtc_enable,
Gustavo Padovan3fc48672015-06-01 12:04:51 -0300110 .disable = exynos_drm_crtc_disable,
Inki Dae1c248b72011-10-04 19:19:01 +0900111 .mode_fixup = exynos_drm_crtc_mode_fixup,
Gustavo Padovan199329c2015-06-01 12:04:43 -0300112 .mode_set_nofb = exynos_drm_crtc_mode_set_nofb,
Gustavo Padovan9d5ab6a2015-06-01 12:04:48 -0300113 .atomic_begin = exynos_crtc_atomic_begin,
114 .atomic_flush = exynos_crtc_atomic_flush,
Inki Dae1c248b72011-10-04 19:19:01 +0900115};
116
Inki Dae1c248b72011-10-04 19:19:01 +0900117static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
118{
119 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
120 struct exynos_drm_private *private = crtc->dev->dev_private;
121
Inki Dae1c248b72011-10-04 19:19:01 +0900122 private->crtc[exynos_crtc->pipe] = NULL;
123
124 drm_crtc_cleanup(crtc);
125 kfree(exynos_crtc);
126}
127
128static struct drm_crtc_funcs exynos_crtc_funcs = {
Gustavo Padovan47a7def2015-06-01 12:04:47 -0300129 .set_config = drm_atomic_helper_set_config,
Gustavo Padovan9d5ab6a2015-06-01 12:04:48 -0300130 .page_flip = drm_atomic_helper_page_flip,
Inki Dae1c248b72011-10-04 19:19:01 +0900131 .destroy = exynos_drm_crtc_destroy,
Gustavo Padovan4ea95262015-06-01 12:04:44 -0300132 .reset = drm_atomic_helper_crtc_reset,
133 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
134 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
Inki Dae1c248b72011-10-04 19:19:01 +0900135};
136
Gustavo Padovan93bca242015-01-18 18:16:23 +0900137struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
Krzysztof Kozlowskif3aaf762015-05-07 09:04:45 +0900138 struct drm_plane *plane,
139 int pipe,
140 enum exynos_drm_output_type type,
141 const struct exynos_drm_crtc_ops *ops,
142 void *ctx)
Inki Dae1c248b72011-10-04 19:19:01 +0900143{
144 struct exynos_drm_crtc *exynos_crtc;
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200145 struct exynos_drm_private *private = drm_dev->dev_private;
Inki Dae1c248b72011-10-04 19:19:01 +0900146 struct drm_crtc *crtc;
Andrzej Hajda72ed6cc2014-09-19 14:58:53 +0200147 int ret;
Inki Dae1c248b72011-10-04 19:19:01 +0900148
Inki Dae1c248b72011-10-04 19:19:01 +0900149 exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +0900150 if (!exynos_crtc)
Gustavo Padovan93bca242015-01-18 18:16:23 +0900151 return ERR_PTR(-ENOMEM);
Inki Dae1c248b72011-10-04 19:19:01 +0900152
Inki Dae20cd2642013-05-21 16:55:58 +0900153 init_waitqueue_head(&exynos_crtc->pending_flip_queue);
Sean Paul080be03d2014-02-19 21:02:55 +0900154
Gustavo Padovane09f2b02014-11-04 18:25:27 -0200155 exynos_crtc->pipe = pipe;
Gustavo Padovan5d1741a2014-11-05 19:51:35 -0200156 exynos_crtc->type = type;
Gustavo Padovan93bca242015-01-18 18:16:23 +0900157 exynos_crtc->ops = ops;
158 exynos_crtc->ctx = ctx;
Joonyoung Shimb5d2eb32012-06-27 14:27:04 +0900159
Gustavo Padovan357193c2014-11-03 18:20:29 -0200160 crtc = &exynos_crtc->base;
Inki Dae1c248b72011-10-04 19:19:01 +0900161
Gustavo Padovane09f2b02014-11-04 18:25:27 -0200162 private->crtc[pipe] = crtc;
Inki Dae1c248b72011-10-04 19:19:01 +0900163
Gustavo Padovaneb88e422014-11-26 16:43:27 -0200164 ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL,
Andrzej Hajda72ed6cc2014-09-19 14:58:53 +0200165 &exynos_crtc_funcs);
166 if (ret < 0)
167 goto err_crtc;
168
Inki Dae1c248b72011-10-04 19:19:01 +0900169 drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
170
Gustavo Padovan93bca242015-01-18 18:16:23 +0900171 return exynos_crtc;
Andrzej Hajda72ed6cc2014-09-19 14:58:53 +0200172
173err_crtc:
174 plane->funcs->destroy(plane);
Andrzej Hajda72ed6cc2014-09-19 14:58:53 +0200175 kfree(exynos_crtc);
Gustavo Padovan93bca242015-01-18 18:16:23 +0900176 return ERR_PTR(ret);
Inki Dae1c248b72011-10-04 19:19:01 +0900177}
178
Sean Paul080be03d2014-02-19 21:02:55 +0900179int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
Inki Dae1c248b72011-10-04 19:19:01 +0900180{
181 struct exynos_drm_private *private = dev->dev_private;
Inki Daeec05da92011-12-06 11:06:54 +0900182 struct exynos_drm_crtc *exynos_crtc =
Sean Paul080be03d2014-02-19 21:02:55 +0900183 to_exynos_crtc(private->crtc[pipe]);
Inki Dae1c248b72011-10-04 19:19:01 +0900184
Gustavo Padovan63498e32015-06-01 12:04:53 -0300185 if (!exynos_crtc->enabled)
Inki Daeec05da92011-12-06 11:06:54 +0900186 return -EPERM;
187
Gustavo Padovan93bca242015-01-18 18:16:23 +0900188 if (exynos_crtc->ops->enable_vblank)
189 exynos_crtc->ops->enable_vblank(exynos_crtc);
Inki Dae1c248b72011-10-04 19:19:01 +0900190
191 return 0;
192}
193
Sean Paul080be03d2014-02-19 21:02:55 +0900194void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
Inki Dae1c248b72011-10-04 19:19:01 +0900195{
196 struct exynos_drm_private *private = dev->dev_private;
Inki Daeec05da92011-12-06 11:06:54 +0900197 struct exynos_drm_crtc *exynos_crtc =
Sean Paul080be03d2014-02-19 21:02:55 +0900198 to_exynos_crtc(private->crtc[pipe]);
Inki Dae1c248b72011-10-04 19:19:01 +0900199
Gustavo Padovan63498e32015-06-01 12:04:53 -0300200 if (!exynos_crtc->enabled)
Inki Daeec05da92011-12-06 11:06:54 +0900201 return;
202
Gustavo Padovan93bca242015-01-18 18:16:23 +0900203 if (exynos_crtc->ops->disable_vblank)
204 exynos_crtc->ops->disable_vblank(exynos_crtc);
Inki Dae1c248b72011-10-04 19:19:01 +0900205}
Rahul Sharma663d8762013-01-03 05:44:04 -0500206
Sean Paul080be03d2014-02-19 21:02:55 +0900207void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe)
Rahul Sharma663d8762013-01-03 05:44:04 -0500208{
209 struct exynos_drm_private *dev_priv = dev->dev_private;
Sean Paul080be03d2014-02-19 21:02:55 +0900210 struct drm_crtc *drm_crtc = dev_priv->crtc[pipe];
Inki Dae20cd2642013-05-21 16:55:58 +0900211 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc);
Rahul Sharma663d8762013-01-03 05:44:04 -0500212 unsigned long flags;
213
Rahul Sharma663d8762013-01-03 05:44:04 -0500214 spin_lock_irqsave(&dev->event_lock, flags);
Mandeep Singh Bainese7527472015-04-01 13:02:12 -0300215 if (exynos_crtc->event) {
Rahul Sharma663d8762013-01-03 05:44:04 -0500216
Mandeep Singh Bainese7527472015-04-01 13:02:12 -0300217 drm_send_vblank_event(dev, -1, exynos_crtc->event);
Sean Paul080be03d2014-02-19 21:02:55 +0900218 drm_vblank_put(dev, pipe);
Inki Dae20cd2642013-05-21 16:55:58 +0900219 wake_up(&exynos_crtc->pending_flip_queue);
Mandeep Singh Bainese7527472015-04-01 13:02:12 -0300220
Rahul Sharma663d8762013-01-03 05:44:04 -0500221 }
222
Mandeep Singh Bainese7527472015-04-01 13:02:12 -0300223 exynos_crtc->event = NULL;
Rahul Sharma663d8762013-01-03 05:44:04 -0500224 spin_unlock_irqrestore(&dev->event_lock, flags);
225}
Sean Paul080be03d2014-02-19 21:02:55 +0900226
Sean Paul080be03d2014-02-19 21:02:55 +0900227void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
228{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900229 struct exynos_drm_crtc *exynos_crtc;
Sean Paul080be03d2014-02-19 21:02:55 +0900230 struct drm_device *dev = fb->dev;
231 struct drm_crtc *crtc;
232
233 /*
234 * make sure that overlay data are updated to real hardware
235 * for all encoders.
236 */
237 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
Gustavo Padovan93bca242015-01-18 18:16:23 +0900238 exynos_crtc = to_exynos_crtc(crtc);
Sean Paul080be03d2014-02-19 21:02:55 +0900239
240 /*
241 * wait for vblank interrupt
242 * - this makes sure that overlay data are updated to
243 * real hardware.
244 */
Gustavo Padovan93bca242015-01-18 18:16:23 +0900245 if (exynos_crtc->ops->wait_for_vblank)
246 exynos_crtc->ops->wait_for_vblank(exynos_crtc);
Sean Paul080be03d2014-02-19 21:02:55 +0900247 }
248}
Inki Daef37cd5e2014-05-09 14:25:20 +0900249
250int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
251 unsigned int out_type)
252{
253 struct drm_crtc *crtc;
254
255 list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
256 struct exynos_drm_crtc *exynos_crtc;
257
258 exynos_crtc = to_exynos_crtc(crtc);
Gustavo Padovan5d1741a2014-11-05 19:51:35 -0200259 if (exynos_crtc->type == out_type)
Gustavo Padovan8a326ed2014-11-04 18:44:47 -0200260 return exynos_crtc->pipe;
Inki Daef37cd5e2014-05-09 14:25:20 +0900261 }
262
263 return -EPERM;
264}
YoungJun Cho5595d4d2014-07-17 18:01:19 +0900265
266void exynos_drm_crtc_te_handler(struct drm_crtc *crtc)
267{
Gustavo Padovan93bca242015-01-18 18:16:23 +0900268 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
YoungJun Cho5595d4d2014-07-17 18:01:19 +0900269
Gustavo Padovan93bca242015-01-18 18:16:23 +0900270 if (exynos_crtc->ops->te_handler)
271 exynos_crtc->ops->te_handler(exynos_crtc);
YoungJun Cho5595d4d2014-07-17 18:01:19 +0900272}