3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 * Seung-Woo Kim <sw0312.kim@samsung.com>
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:
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
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.
30 #include "drm_crtc_helper.h"
32 #include "exynos_drm_drv.h"
33 #include "exynos_drm_fb.h"
34 #include "exynos_drm_encoder.h"
35 #include "exynos_drm_buf.h"
37 #define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\
41 * Exynos specific crtc postion structure.
43 * @fb_x: offset x on a framebuffer to be displyed
44 * - the unit is screen coordinates.
45 * @fb_y: offset y on a framebuffer to be displayed
46 * - the unit is screen coordinates.
47 * @crtc_x: offset x on hardware screen.
48 * @crtc_y: offset y on hardware screen.
49 * @crtc_w: width of hardware screen.
50 * @crtc_h: height of hardware screen.
52 struct exynos_drm_crtc_pos
{
62 * Exynos specific crtc structure.
64 * @drm_crtc: crtc object.
65 * @overlay: contain information common to display controller and hdmi and
66 * contents of this overlay object would be copied to sub driver size.
67 * @pipe: a crtc index created at load() with a new crtc object creation
68 * and the crtc object would be set to private->crtc array
69 * to get a crtc object corresponding to this pipe from private->crtc
70 * array when irq interrupt occured. the reason of using this pipe is that
71 * drm framework doesn't support multiple irq yet.
72 * we can refer to the crtc to current hardware interrupt occured through
75 struct exynos_drm_crtc
{
76 struct drm_crtc drm_crtc
;
77 struct exynos_drm_overlay overlay
;
81 static void exynos_drm_crtc_apply(struct drm_crtc
*crtc
)
83 struct exynos_drm_crtc
*exynos_crtc
= to_exynos_crtc(crtc
);
84 struct exynos_drm_overlay
*overlay
= &exynos_crtc
->overlay
;
86 exynos_drm_fn_encoder(crtc
, overlay
,
87 exynos_drm_encoder_crtc_mode_set
);
88 exynos_drm_fn_encoder(crtc
, NULL
, exynos_drm_encoder_crtc_commit
);
91 static int exynos_drm_overlay_update(struct exynos_drm_overlay
*overlay
,
92 struct drm_framebuffer
*fb
,
93 struct drm_display_mode
*mode
,
94 struct exynos_drm_crtc_pos
*pos
)
96 struct exynos_drm_buf_entry
*entry
;
97 unsigned int actual_w
;
98 unsigned int actual_h
;
100 entry
= exynos_drm_fb_get_buf(fb
);
102 DRM_LOG_KMS("entry is null.\n");
106 overlay
->paddr
= entry
->paddr
;
107 overlay
->vaddr
= entry
->vaddr
;
109 DRM_DEBUG_KMS("vaddr = 0x%lx, paddr = 0x%lx\n",
110 (unsigned long)overlay
->vaddr
,
111 (unsigned long)overlay
->paddr
);
113 actual_w
= min((mode
->hdisplay
- pos
->crtc_x
), pos
->crtc_w
);
114 actual_h
= min((mode
->vdisplay
- pos
->crtc_y
), pos
->crtc_h
);
116 /* set drm framebuffer data. */
117 overlay
->fb_x
= pos
->fb_x
;
118 overlay
->fb_y
= pos
->fb_y
;
119 overlay
->fb_width
= fb
->width
;
120 overlay
->fb_height
= fb
->height
;
121 overlay
->bpp
= fb
->bits_per_pixel
;
122 overlay
->pitch
= fb
->pitch
;
124 /* set overlay range to be displayed. */
125 overlay
->crtc_x
= pos
->crtc_x
;
126 overlay
->crtc_y
= pos
->crtc_y
;
127 overlay
->crtc_width
= actual_w
;
128 overlay
->crtc_height
= actual_h
;
130 /* set drm mode data. */
131 overlay
->mode_width
= mode
->hdisplay
;
132 overlay
->mode_height
= mode
->vdisplay
;
133 overlay
->refresh
= mode
->vrefresh
;
134 overlay
->scan_flag
= mode
->flags
;
136 DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
137 overlay
->crtc_x
, overlay
->crtc_y
,
138 overlay
->crtc_width
, overlay
->crtc_height
);
143 static int exynos_drm_crtc_update(struct drm_crtc
*crtc
)
145 struct exynos_drm_crtc
*exynos_crtc
;
146 struct exynos_drm_overlay
*overlay
;
147 struct exynos_drm_crtc_pos pos
;
148 struct drm_display_mode
*mode
= &crtc
->mode
;
149 struct drm_framebuffer
*fb
= crtc
->fb
;
154 exynos_crtc
= to_exynos_crtc(crtc
);
155 overlay
= &exynos_crtc
->overlay
;
157 memset(&pos
, 0, sizeof(struct exynos_drm_crtc_pos
));
159 /* it means the offset of framebuffer to be displayed. */
163 /* OSD position to be displayed. */
166 pos
.crtc_w
= fb
->width
- crtc
->x
;
167 pos
.crtc_h
= fb
->height
- crtc
->y
;
169 return exynos_drm_overlay_update(overlay
, crtc
->fb
, mode
, &pos
);
172 static void exynos_drm_crtc_dpms(struct drm_crtc
*crtc
, int mode
)
174 DRM_DEBUG_KMS("%s\n", __FILE__
);
179 static void exynos_drm_crtc_prepare(struct drm_crtc
*crtc
)
181 DRM_DEBUG_KMS("%s\n", __FILE__
);
183 /* drm framework doesn't check NULL. */
186 static void exynos_drm_crtc_commit(struct drm_crtc
*crtc
)
188 DRM_DEBUG_KMS("%s\n", __FILE__
);
190 /* drm framework doesn't check NULL. */
194 exynos_drm_crtc_mode_fixup(struct drm_crtc
*crtc
,
195 struct drm_display_mode
*mode
,
196 struct drm_display_mode
*adjusted_mode
)
198 DRM_DEBUG_KMS("%s\n", __FILE__
);
200 /* drm framework doesn't check NULL */
205 exynos_drm_crtc_mode_set(struct drm_crtc
*crtc
, struct drm_display_mode
*mode
,
206 struct drm_display_mode
*adjusted_mode
, int x
, int y
,
207 struct drm_framebuffer
*old_fb
)
209 DRM_DEBUG_KMS("%s\n", __FILE__
);
211 mode
= adjusted_mode
;
213 return exynos_drm_crtc_update(crtc
);
216 static int exynos_drm_crtc_mode_set_base(struct drm_crtc
*crtc
, int x
, int y
,
217 struct drm_framebuffer
*old_fb
)
221 DRM_DEBUG_KMS("%s\n", __FILE__
);
223 ret
= exynos_drm_crtc_update(crtc
);
227 exynos_drm_crtc_apply(crtc
);
232 static void exynos_drm_crtc_load_lut(struct drm_crtc
*crtc
)
234 DRM_DEBUG_KMS("%s\n", __FILE__
);
235 /* drm framework doesn't check NULL */
238 static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs
= {
239 .dpms
= exynos_drm_crtc_dpms
,
240 .prepare
= exynos_drm_crtc_prepare
,
241 .commit
= exynos_drm_crtc_commit
,
242 .mode_fixup
= exynos_drm_crtc_mode_fixup
,
243 .mode_set
= exynos_drm_crtc_mode_set
,
244 .mode_set_base
= exynos_drm_crtc_mode_set_base
,
245 .load_lut
= exynos_drm_crtc_load_lut
,
248 static int exynos_drm_crtc_page_flip(struct drm_crtc
*crtc
,
249 struct drm_framebuffer
*fb
,
250 struct drm_pending_vblank_event
*event
)
252 struct drm_device
*dev
= crtc
->dev
;
253 struct exynos_drm_private
*dev_priv
= dev
->dev_private
;
254 struct exynos_drm_crtc
*exynos_crtc
= to_exynos_crtc(crtc
);
255 struct drm_framebuffer
*old_fb
= crtc
->fb
;
258 DRM_DEBUG_KMS("%s\n", __FILE__
);
260 mutex_lock(&dev
->struct_mutex
);
264 * the pipe from user always is 0 so we can set pipe number
265 * of current owner to event.
267 event
->pipe
= exynos_crtc
->pipe
;
269 list_add_tail(&event
->base
.link
,
270 &dev_priv
->pageflip_event_list
);
272 ret
= drm_vblank_get(dev
, exynos_crtc
->pipe
);
274 DRM_DEBUG("failed to acquire vblank counter\n");
275 list_del(&event
->base
.link
);
281 ret
= exynos_drm_crtc_update(crtc
);
284 drm_vblank_put(dev
, exynos_crtc
->pipe
);
285 list_del(&event
->base
.link
);
291 * the values related to a buffer of the drm framebuffer
292 * to be applied should be set at here. because these values
293 * first, are set to shadow registers and then to
294 * real registers at vsync front porch period.
296 exynos_drm_crtc_apply(crtc
);
299 mutex_unlock(&dev
->struct_mutex
);
303 static void exynos_drm_crtc_destroy(struct drm_crtc
*crtc
)
305 struct exynos_drm_crtc
*exynos_crtc
= to_exynos_crtc(crtc
);
306 struct exynos_drm_private
*private = crtc
->dev
->dev_private
;
308 DRM_DEBUG_KMS("%s\n", __FILE__
);
310 private->crtc
[exynos_crtc
->pipe
] = NULL
;
312 drm_crtc_cleanup(crtc
);
316 static struct drm_crtc_funcs exynos_crtc_funcs
= {
317 .set_config
= drm_crtc_helper_set_config
,
318 .page_flip
= exynos_drm_crtc_page_flip
,
319 .destroy
= exynos_drm_crtc_destroy
,
322 struct exynos_drm_overlay
*get_exynos_drm_overlay(struct drm_device
*dev
,
323 struct drm_crtc
*crtc
)
325 struct exynos_drm_crtc
*exynos_crtc
= to_exynos_crtc(crtc
);
327 return &exynos_crtc
->overlay
;
330 int exynos_drm_crtc_create(struct drm_device
*dev
, unsigned int nr
)
332 struct exynos_drm_crtc
*exynos_crtc
;
333 struct exynos_drm_private
*private = dev
->dev_private
;
334 struct drm_crtc
*crtc
;
336 DRM_DEBUG_KMS("%s\n", __FILE__
);
338 exynos_crtc
= kzalloc(sizeof(*exynos_crtc
), GFP_KERNEL
);
340 DRM_ERROR("failed to allocate exynos crtc\n");
344 exynos_crtc
->pipe
= nr
;
345 crtc
= &exynos_crtc
->drm_crtc
;
347 private->crtc
[nr
] = crtc
;
349 drm_crtc_init(dev
, crtc
, &exynos_crtc_funcs
);
350 drm_crtc_helper_add(crtc
, &exynos_crtc_helper_funcs
);
355 int exynos_drm_crtc_enable_vblank(struct drm_device
*dev
, int crtc
)
357 struct exynos_drm_private
*private = dev
->dev_private
;
359 DRM_DEBUG_KMS("%s\n", __FILE__
);
361 exynos_drm_fn_encoder(private->crtc
[crtc
], &crtc
,
362 exynos_drm_enable_vblank
);
367 void exynos_drm_crtc_disable_vblank(struct drm_device
*dev
, int crtc
)
369 struct exynos_drm_private
*private = dev
->dev_private
;
371 DRM_DEBUG_KMS("%s\n", __FILE__
);
373 exynos_drm_fn_encoder(private->crtc
[crtc
], &crtc
,
374 exynos_drm_disable_vblank
);
377 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
378 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
379 MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
380 MODULE_DESCRIPTION("Samsung SoC DRM CRTC Driver");
381 MODULE_LICENSE("GPL");