• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* exynos_drm_encoder.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_crtc.h"
34 #include "exynos_drm_encoder.h"
35 
36 #define to_exynos_encoder(x)	container_of(x, struct exynos_drm_encoder,\
37 				drm_encoder)
38 
39 /*
40  * exynos specific encoder structure.
41  *
42  * @drm_encoder: encoder object.
43  * @manager: specific encoder has its own manager to control a hardware
44  *	appropriately and we can access a hardware drawing on this manager.
45  * @dpms: store the encoder dpms value.
46  */
47 struct exynos_drm_encoder {
48 	struct drm_encoder		drm_encoder;
49 	struct exynos_drm_manager	*manager;
50 	int dpms;
51 };
52 
exynos_drm_display_power(struct drm_encoder * encoder,int mode)53 static void exynos_drm_display_power(struct drm_encoder *encoder, int mode)
54 {
55 	struct drm_device *dev = encoder->dev;
56 	struct drm_connector *connector;
57 	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
58 
59 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
60 		if (connector->encoder == encoder) {
61 			struct exynos_drm_display_ops *display_ops =
62 							manager->display_ops;
63 
64 			DRM_DEBUG_KMS("connector[%d] dpms[%d]\n",
65 					connector->base.id, mode);
66 			if (display_ops && display_ops->power_on)
67 				display_ops->power_on(manager->dev, mode);
68 		}
69 	}
70 }
71 
exynos_drm_encoder_dpms(struct drm_encoder * encoder,int mode)72 static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
73 {
74 	struct drm_device *dev = encoder->dev;
75 	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
76 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
77 	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
78 
79 	DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode);
80 
81 	if (exynos_encoder->dpms == mode) {
82 		DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
83 		return;
84 	}
85 
86 	mutex_lock(&dev->struct_mutex);
87 
88 	switch (mode) {
89 	case DRM_MODE_DPMS_ON:
90 		if (manager_ops && manager_ops->apply)
91 			manager_ops->apply(manager->dev);
92 		exynos_drm_display_power(encoder, mode);
93 		exynos_encoder->dpms = mode;
94 		break;
95 	case DRM_MODE_DPMS_STANDBY:
96 	case DRM_MODE_DPMS_SUSPEND:
97 	case DRM_MODE_DPMS_OFF:
98 		exynos_drm_display_power(encoder, mode);
99 		exynos_encoder->dpms = mode;
100 		break;
101 	default:
102 		DRM_ERROR("unspecified mode %d\n", mode);
103 		break;
104 	}
105 
106 	mutex_unlock(&dev->struct_mutex);
107 }
108 
109 static bool
exynos_drm_encoder_mode_fixup(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)110 exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
111 			       struct drm_display_mode *mode,
112 			       struct drm_display_mode *adjusted_mode)
113 {
114 	struct drm_device *dev = encoder->dev;
115 	struct drm_connector *connector;
116 	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
117 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
118 
119 	DRM_DEBUG_KMS("%s\n", __FILE__);
120 
121 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
122 		if (connector->encoder == encoder)
123 			if (manager_ops && manager_ops->mode_fixup)
124 				manager_ops->mode_fixup(manager->dev, connector,
125 							mode, adjusted_mode);
126 	}
127 
128 	return true;
129 }
130 
exynos_drm_encoder_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)131 static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
132 					 struct drm_display_mode *mode,
133 					 struct drm_display_mode *adjusted_mode)
134 {
135 	struct drm_device *dev = encoder->dev;
136 	struct drm_connector *connector;
137 	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
138 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
139 	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
140 	struct exynos_drm_overlay *overlay = get_exynos_drm_overlay(dev,
141 						encoder->crtc);
142 
143 	DRM_DEBUG_KMS("%s\n", __FILE__);
144 
145 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
146 		if (connector->encoder == encoder) {
147 			if (manager_ops && manager_ops->mode_set)
148 				manager_ops->mode_set(manager->dev,
149 							adjusted_mode);
150 
151 			if (overlay_ops && overlay_ops->mode_set)
152 				overlay_ops->mode_set(manager->dev, overlay);
153 		}
154 	}
155 }
156 
exynos_drm_encoder_prepare(struct drm_encoder * encoder)157 static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
158 {
159 	DRM_DEBUG_KMS("%s\n", __FILE__);
160 
161 	/* drm framework doesn't check NULL. */
162 }
163 
exynos_drm_encoder_commit(struct drm_encoder * encoder)164 static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
165 {
166 	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
167 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
168 
169 	DRM_DEBUG_KMS("%s\n", __FILE__);
170 
171 	if (manager_ops && manager_ops->commit)
172 		manager_ops->commit(manager->dev);
173 }
174 
175 static struct drm_crtc *
exynos_drm_encoder_get_crtc(struct drm_encoder * encoder)176 exynos_drm_encoder_get_crtc(struct drm_encoder *encoder)
177 {
178 	return encoder->crtc;
179 }
180 
181 static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
182 	.dpms		= exynos_drm_encoder_dpms,
183 	.mode_fixup	= exynos_drm_encoder_mode_fixup,
184 	.mode_set	= exynos_drm_encoder_mode_set,
185 	.prepare	= exynos_drm_encoder_prepare,
186 	.commit		= exynos_drm_encoder_commit,
187 	.get_crtc	= exynos_drm_encoder_get_crtc,
188 };
189 
exynos_drm_encoder_destroy(struct drm_encoder * encoder)190 static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
191 {
192 	struct exynos_drm_encoder *exynos_encoder =
193 		to_exynos_encoder(encoder);
194 
195 	DRM_DEBUG_KMS("%s\n", __FILE__);
196 
197 	exynos_encoder->manager->pipe = -1;
198 
199 	drm_encoder_cleanup(encoder);
200 	kfree(exynos_encoder);
201 }
202 
203 static struct drm_encoder_funcs exynos_encoder_funcs = {
204 	.destroy = exynos_drm_encoder_destroy,
205 };
206 
exynos_drm_encoder_clones(struct drm_encoder * encoder)207 static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
208 {
209 	struct drm_encoder *clone;
210 	struct drm_device *dev = encoder->dev;
211 	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
212 	struct exynos_drm_display_ops *display_ops =
213 				exynos_encoder->manager->display_ops;
214 	unsigned int clone_mask = 0;
215 	int cnt = 0;
216 
217 	list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
218 		switch (display_ops->type) {
219 		case EXYNOS_DISPLAY_TYPE_LCD:
220 		case EXYNOS_DISPLAY_TYPE_HDMI:
221 		case EXYNOS_DISPLAY_TYPE_VIDI:
222 			clone_mask |= (1 << (cnt++));
223 			break;
224 		default:
225 			continue;
226 		}
227 	}
228 
229 	return clone_mask;
230 }
231 
exynos_drm_encoder_setup(struct drm_device * dev)232 void exynos_drm_encoder_setup(struct drm_device *dev)
233 {
234 	struct drm_encoder *encoder;
235 
236 	DRM_DEBUG_KMS("%s\n", __FILE__);
237 
238 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
239 		encoder->possible_clones = exynos_drm_encoder_clones(encoder);
240 }
241 
242 struct drm_encoder *
exynos_drm_encoder_create(struct drm_device * dev,struct exynos_drm_manager * manager,unsigned int possible_crtcs)243 exynos_drm_encoder_create(struct drm_device *dev,
244 			   struct exynos_drm_manager *manager,
245 			   unsigned int possible_crtcs)
246 {
247 	struct drm_encoder *encoder;
248 	struct exynos_drm_encoder *exynos_encoder;
249 
250 	DRM_DEBUG_KMS("%s\n", __FILE__);
251 
252 	if (!manager || !possible_crtcs)
253 		return NULL;
254 
255 	if (!manager->dev)
256 		return NULL;
257 
258 	exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
259 	if (!exynos_encoder) {
260 		DRM_ERROR("failed to allocate encoder\n");
261 		return NULL;
262 	}
263 
264 	exynos_encoder->dpms = DRM_MODE_DPMS_OFF;
265 	exynos_encoder->manager = manager;
266 	encoder = &exynos_encoder->drm_encoder;
267 	encoder->possible_crtcs = possible_crtcs;
268 
269 	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
270 
271 	drm_encoder_init(dev, encoder, &exynos_encoder_funcs,
272 			DRM_MODE_ENCODER_TMDS);
273 
274 	drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
275 
276 	DRM_DEBUG_KMS("encoder has been created\n");
277 
278 	return encoder;
279 }
280 
exynos_drm_get_manager(struct drm_encoder * encoder)281 struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder)
282 {
283 	return to_exynos_encoder(encoder)->manager;
284 }
285 
exynos_drm_fn_encoder(struct drm_crtc * crtc,void * data,void (* fn)(struct drm_encoder *,void *))286 void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
287 			    void (*fn)(struct drm_encoder *, void *))
288 {
289 	struct drm_device *dev = crtc->dev;
290 	struct drm_encoder *encoder;
291 	struct exynos_drm_private *private = dev->dev_private;
292 	struct exynos_drm_manager *manager;
293 
294 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
295 		/*
296 		 * if crtc is detached from encoder, check pipe,
297 		 * otherwise check crtc attached to encoder
298 		 */
299 		if (!encoder->crtc) {
300 			manager = to_exynos_encoder(encoder)->manager;
301 			if (manager->pipe < 0 ||
302 					private->crtc[manager->pipe] != crtc)
303 				continue;
304 		} else {
305 			if (encoder->crtc != crtc)
306 				continue;
307 		}
308 
309 		fn(encoder, data);
310 	}
311 }
312 
exynos_drm_enable_vblank(struct drm_encoder * encoder,void * data)313 void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data)
314 {
315 	struct exynos_drm_manager *manager =
316 		to_exynos_encoder(encoder)->manager;
317 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
318 	int crtc = *(int *)data;
319 
320 	if (manager->pipe == -1)
321 		manager->pipe = crtc;
322 
323 	if (manager_ops->enable_vblank)
324 		manager_ops->enable_vblank(manager->dev);
325 }
326 
exynos_drm_disable_vblank(struct drm_encoder * encoder,void * data)327 void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
328 {
329 	struct exynos_drm_manager *manager =
330 		to_exynos_encoder(encoder)->manager;
331 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
332 	int crtc = *(int *)data;
333 
334 	if (manager->pipe == -1)
335 		manager->pipe = crtc;
336 
337 	if (manager_ops->disable_vblank)
338 		manager_ops->disable_vblank(manager->dev);
339 }
340 
exynos_drm_encoder_crtc_plane_commit(struct drm_encoder * encoder,void * data)341 void exynos_drm_encoder_crtc_plane_commit(struct drm_encoder *encoder,
342 					  void *data)
343 {
344 	struct exynos_drm_manager *manager =
345 		to_exynos_encoder(encoder)->manager;
346 	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
347 	int zpos = DEFAULT_ZPOS;
348 
349 	if (data)
350 		zpos = *(int *)data;
351 
352 	if (overlay_ops && overlay_ops->commit)
353 		overlay_ops->commit(manager->dev, zpos);
354 }
355 
exynos_drm_encoder_crtc_commit(struct drm_encoder * encoder,void * data)356 void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data)
357 {
358 	struct exynos_drm_manager *manager =
359 		to_exynos_encoder(encoder)->manager;
360 	int crtc = *(int *)data;
361 	int zpos = DEFAULT_ZPOS;
362 
363 	DRM_DEBUG_KMS("%s\n", __FILE__);
364 
365 	/*
366 	 * when crtc is detached from encoder, this pipe is used
367 	 * to select manager operation
368 	 */
369 	manager->pipe = crtc;
370 
371 	exynos_drm_encoder_crtc_plane_commit(encoder, &zpos);
372 }
373 
exynos_drm_encoder_dpms_from_crtc(struct drm_encoder * encoder,void * data)374 void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder, void *data)
375 {
376 	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
377 	int mode = *(int *)data;
378 
379 	DRM_DEBUG_KMS("%s\n", __FILE__);
380 
381 	exynos_drm_encoder_dpms(encoder, mode);
382 
383 	exynos_encoder->dpms = mode;
384 }
385 
exynos_drm_encoder_crtc_dpms(struct drm_encoder * encoder,void * data)386 void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
387 {
388 	struct drm_device *dev = encoder->dev;
389 	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
390 	struct exynos_drm_manager *manager = exynos_encoder->manager;
391 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
392 	struct drm_connector *connector;
393 	int mode = *(int *)data;
394 
395 	DRM_DEBUG_KMS("%s\n", __FILE__);
396 
397 	if (manager_ops && manager_ops->dpms)
398 		manager_ops->dpms(manager->dev, mode);
399 
400 	/*
401 	 * set current dpms mode to the connector connected to
402 	 * current encoder. connector->dpms would be checked
403 	 * at drm_helper_connector_dpms()
404 	 */
405 	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
406 		if (connector->encoder == encoder)
407 			connector->dpms = mode;
408 
409 	/*
410 	 * if this condition is ok then it means that the crtc is already
411 	 * detached from encoder and last function for detaching is properly
412 	 * done, so clear pipe from manager to prevent repeated call.
413 	 */
414 	if (mode > DRM_MODE_DPMS_ON) {
415 		if (!encoder->crtc)
416 			manager->pipe = -1;
417 	}
418 }
419 
exynos_drm_encoder_crtc_mode_set(struct drm_encoder * encoder,void * data)420 void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data)
421 {
422 	struct exynos_drm_manager *manager =
423 		to_exynos_encoder(encoder)->manager;
424 	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
425 	struct exynos_drm_overlay *overlay = data;
426 
427 	if (overlay_ops && overlay_ops->mode_set)
428 		overlay_ops->mode_set(manager->dev, overlay);
429 }
430 
exynos_drm_encoder_crtc_disable(struct drm_encoder * encoder,void * data)431 void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data)
432 {
433 	struct exynos_drm_manager *manager =
434 		to_exynos_encoder(encoder)->manager;
435 	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
436 	int zpos = DEFAULT_ZPOS;
437 
438 	DRM_DEBUG_KMS("\n");
439 
440 	if (data)
441 		zpos = *(int *)data;
442 
443 	if (overlay_ops && overlay_ops->disable)
444 		overlay_ops->disable(manager->dev, zpos);
445 }
446