blob: a5c594b3ee57702a94fc24a1618361b465267dce [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 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
18 * Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 * OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29#include "drmP.h"
30#include "drm_crtc_helper.h"
31
32#include "exynos_drm_drv.h"
Inki Dae1c248b72011-10-04 19:19:01 +090033#include "exynos_drm_encoder.h"
Joonyoung Shimb5d2eb32012-06-27 14:27:04 +090034#include "exynos_drm_plane.h"
Inki Dae1c248b72011-10-04 19:19:01 +090035
36#define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\
37 drm_crtc)
38
39/*
Inki Dae1c248b72011-10-04 19:19:01 +090040 * Exynos specific crtc structure.
41 *
42 * @drm_crtc: crtc object.
Joonyoung Shimb5d2eb32012-06-27 14:27:04 +090043 * @drm_plane: pointer of private plane object for this crtc
Inki Dae1c248b72011-10-04 19:19:01 +090044 * @pipe: a crtc index created at load() with a new crtc object creation
45 * and the crtc object would be set to private->crtc array
46 * to get a crtc object corresponding to this pipe from private->crtc
47 * array when irq interrupt occured. the reason of using this pipe is that
48 * drm framework doesn't support multiple irq yet.
49 * we can refer to the crtc to current hardware interrupt occured through
50 * this pipe value.
Inki Daeec05da92011-12-06 11:06:54 +090051 * @dpms: store the crtc dpms value
Inki Dae1c248b72011-10-04 19:19:01 +090052 */
53struct exynos_drm_crtc {
54 struct drm_crtc drm_crtc;
Joonyoung Shimb5d2eb32012-06-27 14:27:04 +090055 struct drm_plane *plane;
Inki Dae1c248b72011-10-04 19:19:01 +090056 unsigned int pipe;
Inki Daeec05da92011-12-06 11:06:54 +090057 unsigned int dpms;
Inki Dae1c248b72011-10-04 19:19:01 +090058};
59
Inki Dae1c248b72011-10-04 19:19:01 +090060static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
61{
Inki Daeec05da92011-12-06 11:06:54 +090062 struct drm_device *dev = crtc->dev;
Joonyoung Shimd2716c82011-11-04 17:04:45 +090063 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
Inki Dae1c248b72011-10-04 19:19:01 +090064
Joonyoung Shimd2716c82011-11-04 17:04:45 +090065 DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
66
Inki Daeec05da92011-12-06 11:06:54 +090067 if (exynos_crtc->dpms == mode) {
68 DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
69 return;
70 }
71
72 mutex_lock(&dev->struct_mutex);
73
Joonyoung Shimd2716c82011-11-04 17:04:45 +090074 switch (mode) {
75 case DRM_MODE_DPMS_ON:
Inki Daeec05da92011-12-06 11:06:54 +090076 exynos_drm_fn_encoder(crtc, &mode,
77 exynos_drm_encoder_crtc_dpms);
78 exynos_crtc->dpms = mode;
Joonyoung Shimd2716c82011-11-04 17:04:45 +090079 break;
80 case DRM_MODE_DPMS_STANDBY:
81 case DRM_MODE_DPMS_SUSPEND:
82 case DRM_MODE_DPMS_OFF:
Inki Daeec05da92011-12-06 11:06:54 +090083 exynos_drm_fn_encoder(crtc, &mode,
84 exynos_drm_encoder_crtc_dpms);
85 exynos_crtc->dpms = mode;
Joonyoung Shimd2716c82011-11-04 17:04:45 +090086 break;
87 default:
Inki Daeec05da92011-12-06 11:06:54 +090088 DRM_ERROR("unspecified mode %d\n", mode);
Joonyoung Shimd2716c82011-11-04 17:04:45 +090089 break;
90 }
Inki Daeec05da92011-12-06 11:06:54 +090091
92 mutex_unlock(&dev->struct_mutex);
Inki Dae1c248b72011-10-04 19:19:01 +090093}
94
95static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
96{
97 DRM_DEBUG_KMS("%s\n", __FILE__);
98
99 /* drm framework doesn't check NULL. */
100}
101
102static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
103{
Joonyoung Shimd2716c82011-11-04 17:04:45 +0900104 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
105
Inki Dae1c248b72011-10-04 19:19:01 +0900106 DRM_DEBUG_KMS("%s\n", __FILE__);
107
Joonyoung Shim4070d212012-06-27 14:27:05 +0900108 exynos_plane_commit(exynos_crtc->plane);
Inki Dae1c248b72011-10-04 19:19:01 +0900109}
110
111static bool
112exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc,
Laurent Pincharte811f5a2012-07-17 17:56:50 +0200113 const struct drm_display_mode *mode,
Inki Dae1c248b72011-10-04 19:19:01 +0900114 struct drm_display_mode *adjusted_mode)
115{
116 DRM_DEBUG_KMS("%s\n", __FILE__);
117
118 /* drm framework doesn't check NULL */
119 return true;
120}
121
122static int
123exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
124 struct drm_display_mode *adjusted_mode, int x, int y,
125 struct drm_framebuffer *old_fb)
126{
Joonyoung Shimaeb29222012-06-27 14:27:01 +0900127 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
Joonyoung Shim4070d212012-06-27 14:27:05 +0900128 struct drm_plane *plane = exynos_crtc->plane;
129 unsigned int crtc_w;
130 unsigned int crtc_h;
Joonyoung Shimd249ce02012-06-27 14:27:02 +0900131 int pipe = exynos_crtc->pipe;
Joonyoung Shimaeb29222012-06-27 14:27:01 +0900132 int ret;
133
Inki Dae1c248b72011-10-04 19:19:01 +0900134 DRM_DEBUG_KMS("%s\n", __FILE__);
135
Joonyoung Shimbebab8f2012-06-27 14:27:07 +0900136 exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
137
Inki Dae1de425b2012-03-16 18:47:04 +0900138 /*
139 * copy the mode data adjusted by mode_fixup() into crtc->mode
140 * so that hardware can be seet to proper mode.
141 */
142 memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
Inki Dae1c248b72011-10-04 19:19:01 +0900143
Joonyoung Shim4070d212012-06-27 14:27:05 +0900144 crtc_w = crtc->fb->width - x;
145 crtc_h = crtc->fb->height - y;
146
147 ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
148 x, y, crtc_w, crtc_h);
Joonyoung Shimaeb29222012-06-27 14:27:01 +0900149 if (ret)
150 return ret;
151
Joonyoung Shim4070d212012-06-27 14:27:05 +0900152 plane->crtc = crtc;
153 plane->fb = crtc->fb;
154
Joonyoung Shimd249ce02012-06-27 14:27:02 +0900155 exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe);
Joonyoung Shimaeb29222012-06-27 14:27:01 +0900156
157 return 0;
Inki Dae1c248b72011-10-04 19:19:01 +0900158}
159
160static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
161 struct drm_framebuffer *old_fb)
162{
Joonyoung Shim4070d212012-06-27 14:27:05 +0900163 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
164 struct drm_plane *plane = exynos_crtc->plane;
165 unsigned int crtc_w;
166 unsigned int crtc_h;
Inki Dae1c248b72011-10-04 19:19:01 +0900167 int ret;
168
169 DRM_DEBUG_KMS("%s\n", __FILE__);
170
Joonyoung Shim4070d212012-06-27 14:27:05 +0900171 crtc_w = crtc->fb->width - x;
172 crtc_h = crtc->fb->height - y;
173
174 ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
175 x, y, crtc_w, crtc_h);
Inki Dae1c248b72011-10-04 19:19:01 +0900176 if (ret)
177 return ret;
178
Joonyoung Shimbebab8f2012-06-27 14:27:07 +0900179 exynos_drm_crtc_commit(crtc);
Inki Dae1c248b72011-10-04 19:19:01 +0900180
Joonyoung Shim4070d212012-06-27 14:27:05 +0900181 return 0;
Inki Dae1c248b72011-10-04 19:19:01 +0900182}
183
184static void exynos_drm_crtc_load_lut(struct drm_crtc *crtc)
185{
186 DRM_DEBUG_KMS("%s\n", __FILE__);
187 /* drm framework doesn't check NULL */
188}
189
190static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
191 .dpms = exynos_drm_crtc_dpms,
192 .prepare = exynos_drm_crtc_prepare,
193 .commit = exynos_drm_crtc_commit,
194 .mode_fixup = exynos_drm_crtc_mode_fixup,
195 .mode_set = exynos_drm_crtc_mode_set,
196 .mode_set_base = exynos_drm_crtc_mode_set_base,
197 .load_lut = exynos_drm_crtc_load_lut,
198};
199
200static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
201 struct drm_framebuffer *fb,
202 struct drm_pending_vblank_event *event)
203{
204 struct drm_device *dev = crtc->dev;
205 struct exynos_drm_private *dev_priv = dev->dev_private;
206 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
207 struct drm_framebuffer *old_fb = crtc->fb;
208 int ret = -EINVAL;
209
210 DRM_DEBUG_KMS("%s\n", __FILE__);
211
212 mutex_lock(&dev->struct_mutex);
213
Inki Daeccf4d882011-10-14 13:29:51 +0900214 if (event) {
215 /*
216 * the pipe from user always is 0 so we can set pipe number
217 * of current owner to event.
218 */
219 event->pipe = exynos_crtc->pipe;
220
Inki Dae1c248b72011-10-04 19:19:01 +0900221 ret = drm_vblank_get(dev, exynos_crtc->pipe);
222 if (ret) {
223 DRM_DEBUG("failed to acquire vblank counter\n");
Inki Daeccf4d882011-10-14 13:29:51 +0900224 list_del(&event->base.link);
225
Inki Dae1c248b72011-10-04 19:19:01 +0900226 goto out;
227 }
228
Inki Daec5614ae2012-02-15 11:25:20 +0900229 list_add_tail(&event->base.link,
230 &dev_priv->pageflip_event_list);
231
Inki Dae1c248b72011-10-04 19:19:01 +0900232 crtc->fb = fb;
Joonyoung Shim4070d212012-06-27 14:27:05 +0900233 ret = exynos_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y,
234 NULL);
Inki Dae1c248b72011-10-04 19:19:01 +0900235 if (ret) {
236 crtc->fb = old_fb;
237 drm_vblank_put(dev, exynos_crtc->pipe);
Inki Daeccf4d882011-10-14 13:29:51 +0900238 list_del(&event->base.link);
Inki Dae1c248b72011-10-04 19:19:01 +0900239
240 goto out;
241 }
Inki Dae1c248b72011-10-04 19:19:01 +0900242 }
243out:
244 mutex_unlock(&dev->struct_mutex);
245 return ret;
246}
247
248static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
249{
250 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
251 struct exynos_drm_private *private = crtc->dev->dev_private;
252
253 DRM_DEBUG_KMS("%s\n", __FILE__);
254
255 private->crtc[exynos_crtc->pipe] = NULL;
256
257 drm_crtc_cleanup(crtc);
258 kfree(exynos_crtc);
259}
260
261static struct drm_crtc_funcs exynos_crtc_funcs = {
262 .set_config = drm_crtc_helper_set_config,
263 .page_flip = exynos_drm_crtc_page_flip,
264 .destroy = exynos_drm_crtc_destroy,
265};
266
Inki Dae1c248b72011-10-04 19:19:01 +0900267int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
268{
269 struct exynos_drm_crtc *exynos_crtc;
270 struct exynos_drm_private *private = dev->dev_private;
271 struct drm_crtc *crtc;
272
273 DRM_DEBUG_KMS("%s\n", __FILE__);
274
275 exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
276 if (!exynos_crtc) {
277 DRM_ERROR("failed to allocate exynos crtc\n");
278 return -ENOMEM;
279 }
280
281 exynos_crtc->pipe = nr;
Inki Daeec05da92011-12-06 11:06:54 +0900282 exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
Joonyoung Shimb5d2eb32012-06-27 14:27:04 +0900283 exynos_crtc->plane = exynos_plane_init(dev, 1 << nr, true);
284 if (!exynos_crtc->plane) {
285 kfree(exynos_crtc);
286 return -ENOMEM;
287 }
288
Inki Dae1c248b72011-10-04 19:19:01 +0900289 crtc = &exynos_crtc->drm_crtc;
290
291 private->crtc[nr] = crtc;
292
293 drm_crtc_init(dev, crtc, &exynos_crtc_funcs);
294 drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
295
296 return 0;
297}
298
299int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
300{
301 struct exynos_drm_private *private = dev->dev_private;
Inki Daeec05da92011-12-06 11:06:54 +0900302 struct exynos_drm_crtc *exynos_crtc =
303 to_exynos_crtc(private->crtc[crtc]);
Inki Dae1c248b72011-10-04 19:19:01 +0900304
305 DRM_DEBUG_KMS("%s\n", __FILE__);
306
Inki Daeec05da92011-12-06 11:06:54 +0900307 if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
308 return -EPERM;
309
Inki Dae1c248b72011-10-04 19:19:01 +0900310 exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
311 exynos_drm_enable_vblank);
312
313 return 0;
314}
315
316void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
317{
318 struct exynos_drm_private *private = dev->dev_private;
Inki Daeec05da92011-12-06 11:06:54 +0900319 struct exynos_drm_crtc *exynos_crtc =
320 to_exynos_crtc(private->crtc[crtc]);
Inki Dae1c248b72011-10-04 19:19:01 +0900321
322 DRM_DEBUG_KMS("%s\n", __FILE__);
323
Inki Daeec05da92011-12-06 11:06:54 +0900324 if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
325 return;
326
Inki Dae1c248b72011-10-04 19:19:01 +0900327 exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
328 exynos_drm_disable_vblank);
329}