| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | /* exynos_drm_crtc.c
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (c) 2011 Samsung Electronics Co., Ltd. | 
					
						
							|  |  |  |  * Authors: | 
					
						
							|  |  |  |  *	Inki Dae <inki.dae@samsung.com> | 
					
						
							|  |  |  |  *	Joonyoung Shim <jy0922.shim@samsung.com> | 
					
						
							|  |  |  |  *	Seung-Woo Kim <sw0312.kim@samsung.com> | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2012-12-18 02:30:17 +09:00
										 |  |  |  * This program is free software; you can redistribute  it and/or modify it | 
					
						
							|  |  |  |  * under  the terms of  the GNU General  Public License as published by the | 
					
						
							|  |  |  |  * Free Software Foundation;  either version 2 of the  License, or (at your | 
					
						
							|  |  |  |  * option) any later version. | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 18:01:07 +01:00
										 |  |  | #include <drm/drmP.h>
 | 
					
						
							|  |  |  | #include <drm/drm_crtc_helper.h>
 | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-13 00:46:40 +01:00
										 |  |  | #include "exynos_drm_crtc.h"
 | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | #include "exynos_drm_drv.h"
 | 
					
						
							|  |  |  | #include "exynos_drm_encoder.h"
 | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:04 +09:00
										 |  |  | #include "exynos_drm_plane.h"
 | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define to_exynos_crtc(x)	container_of(x, struct exynos_drm_crtc,\
 | 
					
						
							|  |  |  | 				drm_crtc) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:11 +09:00
										 |  |  | enum exynos_crtc_mode { | 
					
						
							|  |  |  | 	CRTC_MODE_NORMAL,	/* normal mode */ | 
					
						
							|  |  |  | 	CRTC_MODE_BLANK,	/* The private plane of crtc is blank */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Exynos specific crtc structure. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @drm_crtc: crtc object. | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:04 +09:00
										 |  |  |  * @drm_plane: pointer of private plane object for this crtc | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  |  * @manager: the manager associated with this crtc | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  |  * @pipe: a crtc index created at load() with a new crtc object creation | 
					
						
							|  |  |  |  *	and the crtc object would be set to private->crtc array | 
					
						
							|  |  |  |  *	to get a crtc object corresponding to this pipe from private->crtc | 
					
						
							| 
									
										
										
										
											2013-10-24 16:02:57 +09:00
										 |  |  |  *	array when irq interrupt occurred. the reason of using this pipe is that | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  |  *	drm framework doesn't support multiple irq yet. | 
					
						
							| 
									
										
										
										
											2013-10-24 16:02:57 +09:00
										 |  |  |  *	we can refer to the crtc to current hardware interrupt occurred through | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  |  *	this pipe value. | 
					
						
							| 
									
										
										
										
											2011-12-06 11:06:54 +09:00
										 |  |  |  * @dpms: store the crtc dpms value | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:11 +09:00
										 |  |  |  * @mode: store the crtc mode value | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  |  */ | 
					
						
							|  |  |  | struct exynos_drm_crtc { | 
					
						
							|  |  |  | 	struct drm_crtc			drm_crtc; | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:04 +09:00
										 |  |  | 	struct drm_plane		*plane; | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 	struct exynos_drm_manager	*manager; | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 	unsigned int			pipe; | 
					
						
							| 
									
										
										
										
											2011-12-06 11:06:54 +09:00
										 |  |  | 	unsigned int			dpms; | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:11 +09:00
										 |  |  | 	enum exynos_crtc_mode		mode; | 
					
						
							| 
									
										
										
										
											2013-05-21 16:55:58 +09:00
										 |  |  | 	wait_queue_head_t		pending_flip_queue; | 
					
						
							|  |  |  | 	atomic_t			pending_flip; | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-11-04 17:04:45 +09:00
										 |  |  | 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 	struct exynos_drm_manager *manager = exynos_crtc->manager; | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-04 17:04:45 +09:00
										 |  |  | 	DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-06 11:06:54 +09:00
										 |  |  | 	if (exynos_crtc->dpms == mode) { | 
					
						
							|  |  |  | 		DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n"); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-21 16:55:58 +09:00
										 |  |  | 	if (mode > DRM_MODE_DPMS_ON) { | 
					
						
							|  |  |  | 		/* wait for the completion of page flip. */ | 
					
						
							| 
									
										
										
										
											2014-07-17 18:01:17 +09:00
										 |  |  | 		if (!wait_event_timeout(exynos_crtc->pending_flip_queue, | 
					
						
							|  |  |  | 				!atomic_read(&exynos_crtc->pending_flip), | 
					
						
							|  |  |  | 				HZ/20)) | 
					
						
							|  |  |  | 			atomic_set(&exynos_crtc->pending_flip, 0); | 
					
						
							| 
									
										
										
										
											2013-05-21 16:55:58 +09:00
										 |  |  | 		drm_vblank_off(crtc->dev, exynos_crtc->pipe); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 	if (manager->ops->dpms) | 
					
						
							|  |  |  | 		manager->ops->dpms(manager, mode); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:09 +09:00
										 |  |  | 	exynos_crtc->dpms = mode; | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* drm framework doesn't check NULL. */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void exynos_drm_crtc_commit(struct drm_crtc *crtc) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-11-04 17:04:45 +09:00
										 |  |  | 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 	struct exynos_drm_manager *manager = exynos_crtc->manager; | 
					
						
							| 
									
										
										
										
											2011-11-04 17:04:45 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-20 21:29:25 +09:00
										 |  |  | 	exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON); | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:05 +09:00
										 |  |  | 	exynos_plane_commit(exynos_crtc->plane); | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (manager->ops->commit) | 
					
						
							|  |  |  | 		manager->ops->commit(manager); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:09 +09:00
										 |  |  | 	exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON); | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool | 
					
						
							|  |  |  | exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc, | 
					
						
							| 
									
										
										
										
											2012-07-17 17:56:50 +02:00
										 |  |  | 			    const struct drm_display_mode *mode, | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 			    struct drm_display_mode *adjusted_mode) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-01-30 16:19:19 -05:00
										 |  |  | 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); | 
					
						
							|  |  |  | 	struct exynos_drm_manager *manager = exynos_crtc->manager; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (manager->ops->mode_fixup) | 
					
						
							|  |  |  | 		return manager->ops->mode_fixup(manager, mode, adjusted_mode); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, | 
					
						
							|  |  |  | 			  struct drm_display_mode *adjusted_mode, int x, int y, | 
					
						
							|  |  |  | 			  struct drm_framebuffer *old_fb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:01 +09:00
										 |  |  | 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); | 
					
						
							| 
									
										
										
										
											2014-01-30 16:19:18 -05:00
										 |  |  | 	struct exynos_drm_manager *manager = exynos_crtc->manager; | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:05 +09:00
										 |  |  | 	struct drm_plane *plane = exynos_crtc->plane; | 
					
						
							|  |  |  | 	unsigned int crtc_w; | 
					
						
							|  |  |  | 	unsigned int crtc_h; | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:01 +09:00
										 |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-16 18:47:04 +09:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * copy the mode data adjusted by mode_fixup() into crtc->mode | 
					
						
							|  |  |  | 	 * so that hardware can be seet to proper mode. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode)); | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 15:22:40 -07:00
										 |  |  | 	crtc_w = crtc->primary->fb->width - x; | 
					
						
							|  |  |  | 	crtc_h = crtc->primary->fb->height - y; | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:05 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-30 16:19:18 -05:00
										 |  |  | 	if (manager->ops->mode_set) | 
					
						
							|  |  |  | 		manager->ops->mode_set(manager, &crtc->mode); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 15:22:40 -07:00
										 |  |  | 	ret = exynos_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, crtc_w, crtc_h, | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:05 +09:00
										 |  |  | 				    x, y, crtc_w, crtc_h); | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:01 +09:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:05 +09:00
										 |  |  | 	plane->crtc = crtc; | 
					
						
							| 
									
										
										
										
											2014-04-01 15:22:40 -07:00
										 |  |  | 	plane->fb = crtc->primary->fb; | 
					
						
							| 
									
										
										
										
											2014-04-15 15:33:01 +02:00
										 |  |  | 	drm_framebuffer_reference(plane->fb); | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:05 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:01 +09:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-12 16:09:33 +09:00
										 |  |  | static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y, | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 					  struct drm_framebuffer *old_fb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:05 +09:00
										 |  |  | 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); | 
					
						
							|  |  |  | 	struct drm_plane *plane = exynos_crtc->plane; | 
					
						
							|  |  |  | 	unsigned int crtc_w; | 
					
						
							|  |  |  | 	unsigned int crtc_h; | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-14 13:29:47 +09:00
										 |  |  | 	/* when framebuffer changing is requested, crtc's dpms should be on */ | 
					
						
							|  |  |  | 	if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { | 
					
						
							|  |  |  | 		DRM_ERROR("failed framebuffer changing request.\n"); | 
					
						
							|  |  |  | 		return -EPERM; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 15:22:40 -07:00
										 |  |  | 	crtc_w = crtc->primary->fb->width - x; | 
					
						
							|  |  |  | 	crtc_h = crtc->primary->fb->height - y; | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:05 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 15:22:40 -07:00
										 |  |  | 	ret = exynos_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, crtc_w, crtc_h, | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:05 +09:00
										 |  |  | 				    x, y, crtc_w, crtc_h); | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:07 +09:00
										 |  |  | 	exynos_drm_crtc_commit(crtc); | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:05 +09:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-12 16:09:33 +09:00
										 |  |  | static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | 
					
						
							|  |  |  | 					  struct drm_framebuffer *old_fb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return exynos_drm_crtc_mode_set_commit(crtc, x, y, old_fb); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:10 +09:00
										 |  |  | static void exynos_drm_crtc_disable(struct drm_crtc *crtc) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-01-30 16:19:17 -05:00
										 |  |  | 	struct drm_plane *plane; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:10 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); | 
					
						
							| 
									
										
										
										
											2014-01-30 16:19:17 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 15:22:31 -07:00
										 |  |  | 	drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) { | 
					
						
							| 
									
										
										
										
											2014-01-30 16:19:17 -05:00
										 |  |  | 		if (plane->crtc != crtc) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ret = plane->funcs->disable_plane(plane); | 
					
						
							|  |  |  | 		if (ret) | 
					
						
							|  |  |  | 			DRM_ERROR("Failed to disable plane %d\n", ret); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:10 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { | 
					
						
							|  |  |  | 	.dpms		= exynos_drm_crtc_dpms, | 
					
						
							|  |  |  | 	.prepare	= exynos_drm_crtc_prepare, | 
					
						
							|  |  |  | 	.commit		= exynos_drm_crtc_commit, | 
					
						
							|  |  |  | 	.mode_fixup	= exynos_drm_crtc_mode_fixup, | 
					
						
							|  |  |  | 	.mode_set	= exynos_drm_crtc_mode_set, | 
					
						
							|  |  |  | 	.mode_set_base	= exynos_drm_crtc_mode_set_base, | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:10 +09:00
										 |  |  | 	.disable	= exynos_drm_crtc_disable, | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, | 
					
						
							| 
									
										
										
										
											2013-07-22 18:49:58 -07:00
										 |  |  | 				     struct drm_framebuffer *fb, | 
					
						
							|  |  |  | 				     struct drm_pending_vblank_event *event, | 
					
						
							|  |  |  | 				     uint32_t page_flip_flags) | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct drm_device *dev = crtc->dev; | 
					
						
							|  |  |  | 	struct exynos_drm_private *dev_priv = dev->dev_private; | 
					
						
							|  |  |  | 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); | 
					
						
							| 
									
										
										
										
											2014-04-01 15:22:40 -07:00
										 |  |  | 	struct drm_framebuffer *old_fb = crtc->primary->fb; | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 	int ret = -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-11 18:25:21 +09:00
										 |  |  | 	/* when the page flip is requested, crtc's dpms should be on */ | 
					
						
							|  |  |  | 	if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { | 
					
						
							|  |  |  | 		DRM_ERROR("failed page flip request.\n"); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 	mutex_lock(&dev->struct_mutex); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-14 13:29:51 +09:00
										 |  |  | 	if (event) { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * the pipe from user always is 0 so we can set pipe number | 
					
						
							|  |  |  | 		 * of current owner to event. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		event->pipe = exynos_crtc->pipe; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 		ret = drm_vblank_get(dev, exynos_crtc->pipe); | 
					
						
							|  |  |  | 		if (ret) { | 
					
						
							|  |  |  | 			DRM_DEBUG("failed to acquire vblank counter\n"); | 
					
						
							| 
									
										
										
										
											2011-10-14 13:29:51 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 			goto out; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-02 13:30:47 +02:00
										 |  |  | 		spin_lock_irq(&dev->event_lock); | 
					
						
							| 
									
										
										
										
											2012-02-15 11:25:20 +09:00
										 |  |  | 		list_add_tail(&event->base.link, | 
					
						
							|  |  |  | 				&dev_priv->pageflip_event_list); | 
					
						
							| 
									
										
										
										
											2013-05-21 16:55:58 +09:00
										 |  |  | 		atomic_set(&exynos_crtc->pending_flip, 1); | 
					
						
							| 
									
										
										
										
											2012-11-02 13:30:47 +02:00
										 |  |  | 		spin_unlock_irq(&dev->event_lock); | 
					
						
							| 
									
										
										
										
											2012-02-15 11:25:20 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 15:22:40 -07:00
										 |  |  | 		crtc->primary->fb = fb; | 
					
						
							| 
									
										
										
										
											2013-05-12 16:09:33 +09:00
										 |  |  | 		ret = exynos_drm_crtc_mode_set_commit(crtc, crtc->x, crtc->y, | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:05 +09:00
										 |  |  | 						    NULL); | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 		if (ret) { | 
					
						
							| 
									
										
										
										
											2014-04-01 15:22:40 -07:00
										 |  |  | 			crtc->primary->fb = old_fb; | 
					
						
							| 
									
										
										
										
											2012-11-02 13:30:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			spin_lock_irq(&dev->event_lock); | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 			drm_vblank_put(dev, exynos_crtc->pipe); | 
					
						
							| 
									
										
										
										
											2011-10-14 13:29:51 +09:00
										 |  |  | 			list_del(&event->base.link); | 
					
						
							| 
									
										
										
										
											2014-07-17 18:01:17 +09:00
										 |  |  | 			atomic_set(&exynos_crtc->pending_flip, 0); | 
					
						
							| 
									
										
										
										
											2012-11-02 13:30:47 +02:00
										 |  |  | 			spin_unlock_irq(&dev->event_lock); | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	mutex_unlock(&dev->struct_mutex); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); | 
					
						
							|  |  |  | 	struct exynos_drm_private *private = crtc->dev->dev_private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	private->crtc[exynos_crtc->pipe] = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	drm_crtc_cleanup(crtc); | 
					
						
							|  |  |  | 	kfree(exynos_crtc); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:11 +09:00
										 |  |  | static int exynos_drm_crtc_set_property(struct drm_crtc *crtc, | 
					
						
							|  |  |  | 					struct drm_property *property, | 
					
						
							|  |  |  | 					uint64_t val) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct drm_device *dev = crtc->dev; | 
					
						
							|  |  |  | 	struct exynos_drm_private *dev_priv = dev->dev_private; | 
					
						
							|  |  |  | 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (property == dev_priv->crtc_mode_property) { | 
					
						
							|  |  |  | 		enum exynos_crtc_mode mode = val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (mode == exynos_crtc->mode) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		exynos_crtc->mode = mode; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		switch (mode) { | 
					
						
							|  |  |  | 		case CRTC_MODE_NORMAL: | 
					
						
							|  |  |  | 			exynos_drm_crtc_commit(crtc); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case CRTC_MODE_BLANK: | 
					
						
							|  |  |  | 			exynos_plane_dpms(exynos_crtc->plane, | 
					
						
							|  |  |  | 					  DRM_MODE_DPMS_OFF); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return -EINVAL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | static struct drm_crtc_funcs exynos_crtc_funcs = { | 
					
						
							|  |  |  | 	.set_config	= drm_crtc_helper_set_config, | 
					
						
							|  |  |  | 	.page_flip	= exynos_drm_crtc_page_flip, | 
					
						
							|  |  |  | 	.destroy	= exynos_drm_crtc_destroy, | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:11 +09:00
										 |  |  | 	.set_property	= exynos_drm_crtc_set_property, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct drm_prop_enum_list mode_names[] = { | 
					
						
							|  |  |  | 	{ CRTC_MODE_NORMAL, "normal" }, | 
					
						
							|  |  |  | 	{ CRTC_MODE_BLANK, "blank" }, | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:11 +09:00
										 |  |  | static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct drm_device *dev = crtc->dev; | 
					
						
							|  |  |  | 	struct exynos_drm_private *dev_priv = dev->dev_private; | 
					
						
							|  |  |  | 	struct drm_property *prop; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	prop = dev_priv->crtc_mode_property; | 
					
						
							|  |  |  | 	if (!prop) { | 
					
						
							|  |  |  | 		prop = drm_property_create_enum(dev, 0, "mode", mode_names, | 
					
						
							|  |  |  | 						ARRAY_SIZE(mode_names)); | 
					
						
							|  |  |  | 		if (!prop) | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dev_priv->crtc_mode_property = prop; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	drm_object_attach_property(&crtc->base, prop, 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | int exynos_drm_crtc_create(struct exynos_drm_manager *manager) | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct exynos_drm_crtc *exynos_crtc; | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 	struct exynos_drm_private *private = manager->drm_dev->dev_private; | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 	struct drm_crtc *crtc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2013-08-19 19:04:55 +09:00
										 |  |  | 	if (!exynos_crtc) | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-21 16:55:58 +09:00
										 |  |  | 	init_waitqueue_head(&exynos_crtc->pending_flip_queue); | 
					
						
							|  |  |  | 	atomic_set(&exynos_crtc->pending_flip, 0); | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	exynos_crtc->dpms = DRM_MODE_DPMS_OFF; | 
					
						
							|  |  |  | 	exynos_crtc->manager = manager; | 
					
						
							|  |  |  | 	exynos_crtc->pipe = manager->pipe; | 
					
						
							|  |  |  | 	exynos_crtc->plane = exynos_plane_init(manager->drm_dev, | 
					
						
							|  |  |  | 				1 << manager->pipe, true); | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:04 +09:00
										 |  |  | 	if (!exynos_crtc->plane) { | 
					
						
							|  |  |  | 		kfree(exynos_crtc); | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-09 14:25:20 +09:00
										 |  |  | 	manager->crtc = &exynos_crtc->drm_crtc; | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 	crtc = &exynos_crtc->drm_crtc; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 	private->crtc[manager->pipe] = crtc; | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 	drm_crtc_init(manager->drm_dev, crtc, &exynos_crtc_funcs); | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 	drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-27 14:27:11 +09:00
										 |  |  | 	exynos_drm_crtc_attach_mode_property(crtc); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe) | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct exynos_drm_private *private = dev->dev_private; | 
					
						
							| 
									
										
										
										
											2011-12-06 11:06:54 +09:00
										 |  |  | 	struct exynos_drm_crtc *exynos_crtc = | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 		to_exynos_crtc(private->crtc[pipe]); | 
					
						
							|  |  |  | 	struct exynos_drm_manager *manager = exynos_crtc->manager; | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-06 11:06:54 +09:00
										 |  |  | 	if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) | 
					
						
							|  |  |  | 		return -EPERM; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 	if (manager->ops->enable_vblank) | 
					
						
							|  |  |  | 		manager->ops->enable_vblank(manager); | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct exynos_drm_private *private = dev->dev_private; | 
					
						
							| 
									
										
										
										
											2011-12-06 11:06:54 +09:00
										 |  |  | 	struct exynos_drm_crtc *exynos_crtc = | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 		to_exynos_crtc(private->crtc[pipe]); | 
					
						
							|  |  |  | 	struct exynos_drm_manager *manager = exynos_crtc->manager; | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-06 11:06:54 +09:00
										 |  |  | 	if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 	if (manager->ops->disable_vblank) | 
					
						
							|  |  |  | 		manager->ops->disable_vblank(manager); | 
					
						
							| 
									
										
										
										
											2011-10-04 19:19:01 +09:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-01-03 05:44:04 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe) | 
					
						
							| 
									
										
										
										
											2013-01-03 05:44:04 -05:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct exynos_drm_private *dev_priv = dev->dev_private; | 
					
						
							|  |  |  | 	struct drm_pending_vblank_event *e, *t; | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 	struct drm_crtc *drm_crtc = dev_priv->crtc[pipe]; | 
					
						
							| 
									
										
										
										
											2013-05-21 16:55:58 +09:00
										 |  |  | 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc); | 
					
						
							| 
									
										
										
										
											2013-01-03 05:44:04 -05:00
										 |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&dev->event_lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list, | 
					
						
							|  |  |  | 			base.link) { | 
					
						
							|  |  |  | 		/* if event's pipe isn't same as crtc then ignore it. */ | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 		if (pipe != e->pipe) | 
					
						
							| 
									
										
										
										
											2013-01-03 05:44:04 -05:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-22 11:48:40 +09:00
										 |  |  | 		list_del(&e->base.link); | 
					
						
							|  |  |  | 		drm_send_vblank_event(dev, -1, e); | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 		drm_vblank_put(dev, pipe); | 
					
						
							| 
									
										
										
										
											2013-05-21 16:55:58 +09:00
										 |  |  | 		atomic_set(&exynos_crtc->pending_flip, 0); | 
					
						
							|  |  |  | 		wake_up(&exynos_crtc->pending_flip_queue); | 
					
						
							| 
									
										
										
										
											2013-01-03 05:44:04 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&dev->event_lock, flags); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-19 21:02:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc, | 
					
						
							|  |  |  | 			struct exynos_drm_overlay *overlay) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (manager->ops->win_mode_set) | 
					
						
							|  |  |  | 		manager->ops->win_mode_set(manager, overlay); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (manager->ops->win_commit) | 
					
						
							|  |  |  | 		manager->ops->win_commit(manager, zpos); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (manager->ops->win_enable) | 
					
						
							|  |  |  | 		manager->ops->win_enable(manager, zpos); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (manager->ops->win_disable) | 
					
						
							|  |  |  | 		manager->ops->win_disable(manager, zpos); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct exynos_drm_manager *manager; | 
					
						
							|  |  |  | 	struct drm_device *dev = fb->dev; | 
					
						
							|  |  |  | 	struct drm_crtc *crtc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * make sure that overlay data are updated to real hardware | 
					
						
							|  |  |  | 	 * for all encoders. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 
					
						
							|  |  |  | 		manager = to_exynos_crtc(crtc)->manager; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * wait for vblank interrupt | 
					
						
							|  |  |  | 		 * - this makes sure that overlay data are updated to | 
					
						
							|  |  |  | 		 *	real hardware. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		if (manager->ops->wait_for_vblank) | 
					
						
							|  |  |  | 			manager->ops->wait_for_vblank(manager); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-05-09 14:25:20 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, | 
					
						
							|  |  |  | 					unsigned int out_type) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct drm_crtc *crtc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) { | 
					
						
							|  |  |  | 		struct exynos_drm_crtc *exynos_crtc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		exynos_crtc = to_exynos_crtc(crtc); | 
					
						
							|  |  |  | 		if (exynos_crtc->manager->type == out_type) | 
					
						
							|  |  |  | 			return exynos_crtc->manager->pipe; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return -EPERM; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-07-17 18:01:19 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | void exynos_drm_crtc_te_handler(struct drm_crtc *crtc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (manager->ops->te_handler) | 
					
						
							|  |  |  | 		manager->ops->te_handler(manager); | 
					
						
							|  |  |  | } |