blob: 683ceb0f5277836b8d79fec96f5bee043fd3a07d [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"
33#include "exynos_drm_fb.h"
34#include "exynos_drm_encoder.h"
35
36#define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\
37 drm_crtc)
38
39/*
40 * @fb_x: horizontal position from framebuffer base
41 * @fb_y: vertical position from framebuffer base
42 * @base_x: horizontal position from screen base
43 * @base_y: vertical position from screen base
44 * @crtc_w: width of crtc
45 * @crtc_h: height of crtc
46 */
47struct exynos_drm_crtc_pos {
48 unsigned int fb_x;
49 unsigned int fb_y;
50 unsigned int base_x;
51 unsigned int base_y;
52 unsigned int crtc_w;
53 unsigned int crtc_h;
54};
55
56/*
57 * Exynos specific crtc structure.
58 *
59 * @drm_crtc: crtc object.
60 * @overlay: contain information common to display controller and hdmi and
61 * contents of this overlay object would be copied to sub driver size.
62 * @pipe: a crtc index created at load() with a new crtc object creation
63 * and the crtc object would be set to private->crtc array
64 * to get a crtc object corresponding to this pipe from private->crtc
65 * array when irq interrupt occured. the reason of using this pipe is that
66 * drm framework doesn't support multiple irq yet.
67 * we can refer to the crtc to current hardware interrupt occured through
68 * this pipe value.
69 */
70struct exynos_drm_crtc {
71 struct drm_crtc drm_crtc;
72 struct exynos_drm_overlay overlay;
73 unsigned int pipe;
74};
75
76void exynos_drm_crtc_apply(struct drm_crtc *crtc)
77{
78 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
79 struct exynos_drm_overlay *overlay = &exynos_crtc->overlay;
80
81 exynos_drm_fn_encoder(crtc, overlay,
82 exynos_drm_encoder_crtc_mode_set);
83 exynos_drm_fn_encoder(crtc, NULL, exynos_drm_encoder_crtc_commit);
84}
85
86static void exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
87 struct drm_framebuffer *fb,
88 struct drm_display_mode *mode,
89 struct exynos_drm_crtc_pos *pos)
90{
91 struct exynos_drm_buffer_info buffer_info;
92 unsigned int actual_w = pos->crtc_w;
93 unsigned int actual_h = pos->crtc_h;
94 unsigned int hw_w;
95 unsigned int hw_h;
96
97 /* update buffer address of framebuffer. */
98 exynos_drm_fb_update_buf_off(fb, pos->fb_x, pos->fb_y, &buffer_info);
99 overlay->paddr = buffer_info.paddr;
100 overlay->vaddr = buffer_info.vaddr;
101
102 hw_w = mode->hdisplay - pos->base_x;
103 hw_h = mode->vdisplay - pos->base_y;
104
105 if (actual_w > hw_w)
106 actual_w = hw_w;
107 if (actual_h > hw_h)
108 actual_h = hw_h;
109
110 overlay->offset_x = pos->base_x;
111 overlay->offset_y = pos->base_y;
112 overlay->width = actual_w;
113 overlay->height = actual_h;
114 overlay->bpp = fb->bits_per_pixel;
115
116 DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
117 overlay->offset_x, overlay->offset_y,
118 overlay->width, overlay->height);
119
120 overlay->buf_offsize = fb->width - actual_w;
121 overlay->line_size = actual_w;
122}
123
124static int exynos_drm_crtc_update(struct drm_crtc *crtc)
125{
126 struct exynos_drm_crtc *exynos_crtc;
127 struct exynos_drm_overlay *overlay;
128 struct exynos_drm_crtc_pos pos;
129 struct drm_display_mode *mode = &crtc->mode;
130 struct drm_framebuffer *fb = crtc->fb;
131
132 if (!mode || !fb)
133 return -EINVAL;
134
135 exynos_crtc = to_exynos_crtc(crtc);
136 overlay = &exynos_crtc->overlay;
137
138 memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos));
139 pos.fb_x = crtc->x;
140 pos.fb_y = crtc->y;
141 pos.crtc_w = fb->width - crtc->x;
142 pos.crtc_h = fb->height - crtc->y;
143
144 exynos_drm_overlay_update(overlay, crtc->fb, mode, &pos);
145
146 return 0;
147}
148
149static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
150{
151 DRM_DEBUG_KMS("%s\n", __FILE__);
152
153 /* TODO */
154}
155
156static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
157{
158 DRM_DEBUG_KMS("%s\n", __FILE__);
159
160 /* drm framework doesn't check NULL. */
161}
162
163static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
164{
165 DRM_DEBUG_KMS("%s\n", __FILE__);
166
167 /* drm framework doesn't check NULL. */
168}
169
170static bool
171exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc,
172 struct drm_display_mode *mode,
173 struct drm_display_mode *adjusted_mode)
174{
175 DRM_DEBUG_KMS("%s\n", __FILE__);
176
177 /* drm framework doesn't check NULL */
178 return true;
179}
180
181static int
182exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
183 struct drm_display_mode *adjusted_mode, int x, int y,
184 struct drm_framebuffer *old_fb)
185{
186 DRM_DEBUG_KMS("%s\n", __FILE__);
187
188 mode = adjusted_mode;
189
190 return exynos_drm_crtc_update(crtc);
191}
192
193static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
194 struct drm_framebuffer *old_fb)
195{
196 int ret;
197
198 DRM_DEBUG_KMS("%s\n", __FILE__);
199
200 ret = exynos_drm_crtc_update(crtc);
201 if (ret)
202 return ret;
203
204 exynos_drm_crtc_apply(crtc);
205
206 return ret;
207}
208
209static void exynos_drm_crtc_load_lut(struct drm_crtc *crtc)
210{
211 DRM_DEBUG_KMS("%s\n", __FILE__);
212 /* drm framework doesn't check NULL */
213}
214
215static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
216 .dpms = exynos_drm_crtc_dpms,
217 .prepare = exynos_drm_crtc_prepare,
218 .commit = exynos_drm_crtc_commit,
219 .mode_fixup = exynos_drm_crtc_mode_fixup,
220 .mode_set = exynos_drm_crtc_mode_set,
221 .mode_set_base = exynos_drm_crtc_mode_set_base,
222 .load_lut = exynos_drm_crtc_load_lut,
223};
224
225static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
226 struct drm_framebuffer *fb,
227 struct drm_pending_vblank_event *event)
228{
229 struct drm_device *dev = crtc->dev;
230 struct exynos_drm_private *dev_priv = dev->dev_private;
231 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
232 struct drm_framebuffer *old_fb = crtc->fb;
233 int ret = -EINVAL;
234
235 DRM_DEBUG_KMS("%s\n", __FILE__);
236
237 mutex_lock(&dev->struct_mutex);
238
239 if (event && !dev_priv->pageflip_event) {
240 list_add_tail(&event->base.link,
241 &dev_priv->pageflip_event_list);
242
243 ret = drm_vblank_get(dev, exynos_crtc->pipe);
244 if (ret) {
245 DRM_DEBUG("failed to acquire vblank counter\n");
246 goto out;
247 }
248
249 crtc->fb = fb;
250 ret = exynos_drm_crtc_update(crtc);
251 if (ret) {
252 crtc->fb = old_fb;
253 drm_vblank_put(dev, exynos_crtc->pipe);
254 dev_priv->pageflip_event = false;
255
256 goto out;
257 }
258
259 dev_priv->pageflip_event = true;
260 }
261out:
262 mutex_unlock(&dev->struct_mutex);
263 return ret;
264}
265
266static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
267{
268 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
269 struct exynos_drm_private *private = crtc->dev->dev_private;
270
271 DRM_DEBUG_KMS("%s\n", __FILE__);
272
273 private->crtc[exynos_crtc->pipe] = NULL;
274
275 drm_crtc_cleanup(crtc);
276 kfree(exynos_crtc);
277}
278
279static struct drm_crtc_funcs exynos_crtc_funcs = {
280 .set_config = drm_crtc_helper_set_config,
281 .page_flip = exynos_drm_crtc_page_flip,
282 .destroy = exynos_drm_crtc_destroy,
283};
284
285struct exynos_drm_overlay *get_exynos_drm_overlay(struct drm_device *dev,
286 struct drm_crtc *crtc)
287{
288 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
289
290 return &exynos_crtc->overlay;
291}
292
293int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
294{
295 struct exynos_drm_crtc *exynos_crtc;
296 struct exynos_drm_private *private = dev->dev_private;
297 struct drm_crtc *crtc;
298
299 DRM_DEBUG_KMS("%s\n", __FILE__);
300
301 exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
302 if (!exynos_crtc) {
303 DRM_ERROR("failed to allocate exynos crtc\n");
304 return -ENOMEM;
305 }
306
307 exynos_crtc->pipe = nr;
308 crtc = &exynos_crtc->drm_crtc;
309
310 private->crtc[nr] = crtc;
311
312 drm_crtc_init(dev, crtc, &exynos_crtc_funcs);
313 drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
314
315 return 0;
316}
317
318int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
319{
320 struct exynos_drm_private *private = dev->dev_private;
321
322 DRM_DEBUG_KMS("%s\n", __FILE__);
323
324 exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
325 exynos_drm_enable_vblank);
326
327 return 0;
328}
329
330void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
331{
332 struct exynos_drm_private *private = dev->dev_private;
333
334 DRM_DEBUG_KMS("%s\n", __FILE__);
335
336 exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
337 exynos_drm_disable_vblank);
338}
339
340MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
341MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
342MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
343MODULE_DESCRIPTION("Samsung SoC DRM CRTC Driver");
344MODULE_LICENSE("GPL");