2 * Copyright (C) ROCKCHIP, Inc.
3 * Author:yzq<yzq@rock-chips.com>
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include <drm/drm_crtc_helper.h>
16 #include "rockchip_drm_drv.h"
17 #include "rockchip_drm_encoder.h"
18 #include "rockchip_drm_plane.h"
20 #define to_rockchip_crtc(x) container_of(x, struct rockchip_drm_crtc,\
23 enum rockchip_crtc_mode {
24 CRTC_MODE_NORMAL, /* normal mode */
25 CRTC_MODE_BLANK, /* The private plane of crtc is blank */
29 * Exynos specific crtc structure.
31 * @drm_crtc: crtc object.
32 * @drm_plane: pointer of private plane object for this crtc
33 * @pipe: a crtc index created at load() with a new crtc object creation
34 * and the crtc object would be set to private->crtc array
35 * to get a crtc object corresponding to this pipe from private->crtc
36 * array when irq interrupt occured. the reason of using this pipe is that
37 * drm framework doesn't support multiple irq yet.
38 * we can refer to the crtc to current hardware interrupt occured through
40 * @dpms: store the crtc dpms value
41 * @mode: store the crtc mode value
43 struct rockchip_drm_crtc {
44 struct drm_crtc drm_crtc;
45 struct drm_plane *plane;
48 enum rockchip_crtc_mode mode;
49 wait_queue_head_t pending_flip_queue;
50 atomic_t pending_flip;
53 static void rockchip_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
55 struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
57 // printk(KERN_ERR"crtc[%d] mode[%d]\n", crtc->base.id, mode);
59 if (rockchip_crtc->dpms == mode) {
60 DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
64 if (mode > DRM_MODE_DPMS_ON) {
65 /* wait for the completion of page flip. */
66 wait_event(rockchip_crtc->pending_flip_queue,
67 atomic_read(&rockchip_crtc->pending_flip) == 0);
68 drm_vblank_off(crtc->dev, rockchip_crtc->pipe);
71 rockchip_drm_fn_encoder(crtc, &mode, rockchip_drm_encoder_crtc_dpms);
72 rockchip_crtc->dpms = mode;
75 static void rockchip_drm_crtc_prepare(struct drm_crtc *crtc)
77 DRM_DEBUG_KMS("%s\n", __FILE__);
79 /* drm framework doesn't check NULL. */
82 static void rockchip_drm_crtc_commit(struct drm_crtc *crtc)
84 struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
86 DRM_DEBUG_KMS("%s\n", __FILE__);
88 rockchip_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
89 rockchip_plane_commit(rockchip_crtc->plane);
90 rockchip_plane_dpms(rockchip_crtc->plane, DRM_MODE_DPMS_ON);
94 rockchip_drm_crtc_mode_fixup(struct drm_crtc *crtc,
95 const struct drm_display_mode *mode,
96 struct drm_display_mode *adjusted_mode)
98 DRM_DEBUG_KMS("%s\n", __FILE__);
100 /* drm framework doesn't check NULL */
105 rockchip_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
106 struct drm_display_mode *adjusted_mode, int x, int y,
107 struct drm_framebuffer *old_fb)
109 struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
110 struct drm_plane *plane = rockchip_crtc->plane;
113 int pipe = rockchip_crtc->pipe;
116 DRM_DEBUG_KMS("%s\n", __FILE__);
119 * copy the mode data adjusted by mode_fixup() into crtc->mode
120 * so that hardware can be seet to proper mode.
122 memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
124 crtc_w = crtc->fb->width - x;
125 crtc_h = crtc->fb->height - y;
127 ret = rockchip_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
128 x, y, crtc_w, crtc_h);
133 plane->fb = crtc->fb;
135 rockchip_drm_fn_encoder(crtc, &pipe, rockchip_drm_encoder_crtc_pipe);
140 static int rockchip_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
141 struct drm_framebuffer *old_fb)
143 struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
144 struct drm_plane *plane = rockchip_crtc->plane;
149 DRM_DEBUG_KMS("%s\n", __FILE__);
151 /* when framebuffer changing is requested, crtc's dpms should be on */
152 if (rockchip_crtc->dpms > DRM_MODE_DPMS_ON) {
153 DRM_ERROR("failed framebuffer changing request.\n");
157 crtc_w = crtc->fb->width - x;
158 crtc_h = crtc->fb->height - y;
160 ret = rockchip_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
161 x, y, crtc_w, crtc_h);
165 rockchip_drm_crtc_commit(crtc);
170 static void rockchip_drm_crtc_load_lut(struct drm_crtc *crtc)
172 DRM_DEBUG_KMS("%s\n", __FILE__);
173 /* drm framework doesn't check NULL */
176 static void rockchip_drm_crtc_disable(struct drm_crtc *crtc)
178 struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
180 DRM_DEBUG_KMS("%s\n", __FILE__);
182 rockchip_plane_dpms(rockchip_crtc->plane, DRM_MODE_DPMS_OFF);
183 rockchip_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
186 static struct drm_crtc_helper_funcs rockchip_crtc_helper_funcs = {
187 .dpms = rockchip_drm_crtc_dpms,
188 .prepare = rockchip_drm_crtc_prepare,
189 .commit = rockchip_drm_crtc_commit,
190 .mode_fixup = rockchip_drm_crtc_mode_fixup,
191 .mode_set = rockchip_drm_crtc_mode_set,
192 .mode_set_base = rockchip_drm_crtc_mode_set_base,
193 .load_lut = rockchip_drm_crtc_load_lut,
194 .disable = rockchip_drm_crtc_disable,
197 static int rockchip_drm_crtc_page_flip(struct drm_crtc *crtc,
198 struct drm_framebuffer *fb,
199 struct drm_pending_vblank_event *event)
201 struct drm_device *dev = crtc->dev;
202 struct rockchip_drm_private *dev_priv = dev->dev_private;
203 struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
204 struct drm_framebuffer *old_fb = crtc->fb;
208 DRM_DEBUG_KMS("%s\n", __FILE__);
210 /* when the page flip is requested, crtc's dpms should be on */
211 if (rockchip_crtc->dpms > DRM_MODE_DPMS_ON) {
212 DRM_ERROR("failed page flip request.\n");
216 mutex_lock(&dev->struct_mutex);
220 * the pipe from user always is 0 so we can set pipe number
221 * of current owner to event.
223 event->pipe = rockchip_crtc->pipe;
225 ret = drm_vblank_get(dev, rockchip_crtc->pipe);
227 DRM_DEBUG("failed to acquire vblank counter\n");
232 spin_lock_irq(&dev->event_lock);
233 list_add_tail(&event->base.link,
234 &dev_priv->pageflip_event_list);
235 atomic_set(&rockchip_crtc->pending_flip, 1);
236 spin_unlock_irq(&dev->event_lock);
239 ret = rockchip_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y,
244 spin_lock_irq(&dev->event_lock);
245 drm_vblank_put(dev, rockchip_crtc->pipe);
246 list_del(&event->base.link);
247 spin_unlock_irq(&dev->event_lock);
253 mutex_unlock(&dev->struct_mutex);
257 static void rockchip_drm_crtc_destroy(struct drm_crtc *crtc)
259 struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
260 struct rockchip_drm_private *private = crtc->dev->dev_private;
262 DRM_DEBUG_KMS("%s\n", __FILE__);
264 private->crtc[rockchip_crtc->pipe] = NULL;
266 drm_crtc_cleanup(crtc);
267 kfree(rockchip_crtc);
270 static int rockchip_drm_crtc_set_property(struct drm_crtc *crtc,
271 struct drm_property *property,
274 struct drm_device *dev = crtc->dev;
275 struct rockchip_drm_private *dev_priv = dev->dev_private;
276 struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
278 DRM_DEBUG_KMS("%s\n", __func__);
280 if (property == dev_priv->crtc_mode_property) {
281 enum rockchip_crtc_mode mode = val;
283 if (mode == rockchip_crtc->mode)
286 rockchip_crtc->mode = mode;
289 case CRTC_MODE_NORMAL:
290 rockchip_drm_crtc_commit(crtc);
292 case CRTC_MODE_BLANK:
293 rockchip_plane_dpms(rockchip_crtc->plane,
306 static struct drm_crtc_funcs rockchip_crtc_funcs = {
307 .set_config = drm_crtc_helper_set_config,
308 .page_flip = rockchip_drm_crtc_page_flip,
309 .destroy = rockchip_drm_crtc_destroy,
310 .set_property = rockchip_drm_crtc_set_property,
313 static const struct drm_prop_enum_list mode_names[] = {
314 { CRTC_MODE_NORMAL, "normal" },
315 { CRTC_MODE_BLANK, "blank" },
318 static void rockchip_drm_crtc_attach_mode_property(struct drm_crtc *crtc)
320 struct drm_device *dev = crtc->dev;
321 struct rockchip_drm_private *dev_priv = dev->dev_private;
322 struct drm_property *prop;
324 DRM_DEBUG_KMS("%s\n", __func__);
326 prop = dev_priv->crtc_mode_property;
328 prop = drm_property_create_enum(dev, 0, "mode", mode_names,
329 ARRAY_SIZE(mode_names));
333 dev_priv->crtc_mode_property = prop;
336 drm_object_attach_property(&crtc->base, prop, 0);
339 int rockchip_drm_crtc_create(struct drm_device *dev, unsigned int nr)
341 struct rockchip_drm_crtc *rockchip_crtc;
342 struct rockchip_drm_private *private = dev->dev_private;
343 struct drm_crtc *crtc;
345 DRM_DEBUG_KMS("%s\n", __FILE__);
347 rockchip_crtc = kzalloc(sizeof(*rockchip_crtc), GFP_KERNEL);
348 if (!rockchip_crtc) {
349 DRM_ERROR("failed to allocate rockchip crtc\n");
353 rockchip_crtc->pipe = nr;
354 rockchip_crtc->dpms = DRM_MODE_DPMS_OFF;
355 init_waitqueue_head(&rockchip_crtc->pending_flip_queue);
356 atomic_set(&rockchip_crtc->pending_flip, 0);
357 rockchip_crtc->plane = rockchip_plane_init(dev, 1 << nr, true);
358 if (!rockchip_crtc->plane) {
359 kfree(rockchip_crtc);
363 crtc = &rockchip_crtc->drm_crtc;
365 private->crtc[nr] = crtc;
367 drm_crtc_init(dev, crtc, &rockchip_crtc_funcs);
368 drm_crtc_helper_add(crtc, &rockchip_crtc_helper_funcs);
370 rockchip_drm_crtc_attach_mode_property(crtc);
375 int rockchip_get_crtc_vblank_timestamp(struct drm_device *dev, int crtc,
377 struct timeval *vblank_time,
380 struct rockchip_drm_private *private = dev->dev_private;
381 struct rockchip_drm_crtc *rockchip_crtc =
382 to_rockchip_crtc(private->crtc[crtc]);
384 if (rockchip_crtc->dpms != DRM_MODE_DPMS_ON)
387 rockchip_drm_fn_encoder(private->crtc[crtc], &crtc,
388 rockchip_get_vblank_timestamp);
392 int rockchip_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
394 struct rockchip_drm_private *private = dev->dev_private;
395 struct rockchip_drm_crtc *rockchip_crtc =
396 to_rockchip_crtc(private->crtc[crtc]);
398 DRM_DEBUG_KMS("%s\n", __FILE__);
400 if (rockchip_crtc->dpms != DRM_MODE_DPMS_ON)
403 rockchip_drm_fn_encoder(private->crtc[crtc], &crtc,
404 rockchip_drm_enable_vblank);
409 void rockchip_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
411 struct rockchip_drm_private *private = dev->dev_private;
412 struct rockchip_drm_crtc *rockchip_crtc =
413 to_rockchip_crtc(private->crtc[crtc]);
415 DRM_DEBUG_KMS("%s\n", __FILE__);
417 if (rockchip_crtc->dpms != DRM_MODE_DPMS_ON)
420 rockchip_drm_fn_encoder(private->crtc[crtc], &crtc,
421 rockchip_drm_disable_vblank);
424 void rockchip_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc)
426 struct rockchip_drm_private *dev_priv = dev->dev_private;
427 struct drm_pending_vblank_event *e, *t;
428 struct drm_crtc *drm_crtc = dev_priv->crtc[crtc];
429 struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(drm_crtc);
432 DRM_DEBUG_KMS("%s\n", __FILE__);
434 spin_lock_irqsave(&dev->event_lock, flags);
436 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
438 /* if event's pipe isn't same as crtc then ignore it. */
442 list_del(&e->base.link);
443 drm_send_vblank_event(dev, -1, e);
444 drm_vblank_put(dev, crtc);
445 atomic_set(&rockchip_crtc->pending_flip, 0);
446 wake_up(&rockchip_crtc->pending_flip_queue);
449 spin_unlock_irqrestore(&dev->event_lock, flags);