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 	DRM_DEBUG_KMS("%s\n", __FILE__);
115 
116 	/* drm framework doesn't check NULL. */
117 
118 	return true;
119 }
120 
exynos_drm_encoder_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)121 static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
122 					 struct drm_display_mode *mode,
123 					 struct drm_display_mode *adjusted_mode)
124 {
125 	struct drm_device *dev = encoder->dev;
126 	struct drm_connector *connector;
127 	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
128 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
129 	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
130 	struct exynos_drm_overlay *overlay = get_exynos_drm_overlay(dev,
131 						encoder->crtc);
132 
133 	DRM_DEBUG_KMS("%s\n", __FILE__);
134 
135 	mode = adjusted_mode;
136 
137 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
138 		if (connector->encoder == encoder) {
139 			if (manager_ops && manager_ops->mode_set)
140 				manager_ops->mode_set(manager->dev, mode);
141 
142 			if (overlay_ops && overlay_ops->mode_set)
143 				overlay_ops->mode_set(manager->dev, overlay);
144 		}
145 	}
146 }
147 
exynos_drm_encoder_prepare(struct drm_encoder * encoder)148 static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
149 {
150 	DRM_DEBUG_KMS("%s\n", __FILE__);
151 
152 	/* drm framework doesn't check NULL. */
153 }
154 
exynos_drm_encoder_commit(struct drm_encoder * encoder)155 static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
156 {
157 	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
158 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
159 
160 	DRM_DEBUG_KMS("%s\n", __FILE__);
161 
162 	if (manager_ops && manager_ops->commit)
163 		manager_ops->commit(manager->dev);
164 }
165 
166 static struct drm_crtc *
exynos_drm_encoder_get_crtc(struct drm_encoder * encoder)167 exynos_drm_encoder_get_crtc(struct drm_encoder *encoder)
168 {
169 	return encoder->crtc;
170 }
171 
172 static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
173 	.dpms		= exynos_drm_encoder_dpms,
174 	.mode_fixup	= exynos_drm_encoder_mode_fixup,
175 	.mode_set	= exynos_drm_encoder_mode_set,
176 	.prepare	= exynos_drm_encoder_prepare,
177 	.commit		= exynos_drm_encoder_commit,
178 	.get_crtc	= exynos_drm_encoder_get_crtc,
179 };
180 
exynos_drm_encoder_destroy(struct drm_encoder * encoder)181 static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
182 {
183 	struct exynos_drm_encoder *exynos_encoder =
184 		to_exynos_encoder(encoder);
185 
186 	DRM_DEBUG_KMS("%s\n", __FILE__);
187 
188 	exynos_encoder->manager->pipe = -1;
189 
190 	drm_encoder_cleanup(encoder);
191 	kfree(exynos_encoder);
192 }
193 
194 static struct drm_encoder_funcs exynos_encoder_funcs = {
195 	.destroy = exynos_drm_encoder_destroy,
196 };
197 
exynos_drm_encoder_clones(struct drm_encoder * encoder)198 static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
199 {
200 	struct drm_encoder *clone;
201 	struct drm_device *dev = encoder->dev;
202 	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
203 	struct exynos_drm_display_ops *display_ops =
204 				exynos_encoder->manager->display_ops;
205 	unsigned int clone_mask = 0;
206 	int cnt = 0;
207 
208 	list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
209 		switch (display_ops->type) {
210 		case EXYNOS_DISPLAY_TYPE_LCD:
211 		case EXYNOS_DISPLAY_TYPE_HDMI:
212 			clone_mask |= (1 << (cnt++));
213 			break;
214 		default:
215 			continue;
216 		}
217 	}
218 
219 	return clone_mask;
220 }
221 
exynos_drm_encoder_setup(struct drm_device * dev)222 void exynos_drm_encoder_setup(struct drm_device *dev)
223 {
224 	struct drm_encoder *encoder;
225 
226 	DRM_DEBUG_KMS("%s\n", __FILE__);
227 
228 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
229 		encoder->possible_clones = exynos_drm_encoder_clones(encoder);
230 }
231 
232 struct drm_encoder *
exynos_drm_encoder_create(struct drm_device * dev,struct exynos_drm_manager * manager,unsigned int possible_crtcs)233 exynos_drm_encoder_create(struct drm_device *dev,
234 			   struct exynos_drm_manager *manager,
235 			   unsigned int possible_crtcs)
236 {
237 	struct drm_encoder *encoder;
238 	struct exynos_drm_encoder *exynos_encoder;
239 
240 	DRM_DEBUG_KMS("%s\n", __FILE__);
241 
242 	if (!manager || !possible_crtcs)
243 		return NULL;
244 
245 	if (!manager->dev)
246 		return NULL;
247 
248 	exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
249 	if (!exynos_encoder) {
250 		DRM_ERROR("failed to allocate encoder\n");
251 		return NULL;
252 	}
253 
254 	exynos_encoder->dpms = DRM_MODE_DPMS_OFF;
255 	exynos_encoder->manager = manager;
256 	encoder = &exynos_encoder->drm_encoder;
257 	encoder->possible_crtcs = possible_crtcs;
258 
259 	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
260 
261 	drm_encoder_init(dev, encoder, &exynos_encoder_funcs,
262 			DRM_MODE_ENCODER_TMDS);
263 
264 	drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
265 
266 	DRM_DEBUG_KMS("encoder has been created\n");
267 
268 	return encoder;
269 }
270 
exynos_drm_get_manager(struct drm_encoder * encoder)271 struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder)
272 {
273 	return to_exynos_encoder(encoder)->manager;
274 }
275 
exynos_drm_fn_encoder(struct drm_crtc * crtc,void * data,void (* fn)(struct drm_encoder *,void *))276 void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
277 			    void (*fn)(struct drm_encoder *, void *))
278 {
279 	struct drm_device *dev = crtc->dev;
280 	struct drm_encoder *encoder;
281 	struct exynos_drm_private *private = dev->dev_private;
282 	struct exynos_drm_manager *manager;
283 
284 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
285 		/*
286 		 * if crtc is detached from encoder, check pipe,
287 		 * otherwise check crtc attached to encoder
288 		 */
289 		if (!encoder->crtc) {
290 			manager = to_exynos_encoder(encoder)->manager;
291 			if (manager->pipe < 0 ||
292 					private->crtc[manager->pipe] != crtc)
293 				continue;
294 		} else {
295 			if (encoder->crtc != crtc)
296 				continue;
297 		}
298 
299 		fn(encoder, data);
300 	}
301 }
302 
exynos_drm_enable_vblank(struct drm_encoder * encoder,void * data)303 void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data)
304 {
305 	struct exynos_drm_manager *manager =
306 		to_exynos_encoder(encoder)->manager;
307 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
308 	int crtc = *(int *)data;
309 
310 	if (manager->pipe == -1)
311 		manager->pipe = crtc;
312 
313 	if (manager_ops->enable_vblank)
314 		manager_ops->enable_vblank(manager->dev);
315 }
316 
exynos_drm_disable_vblank(struct drm_encoder * encoder,void * data)317 void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
318 {
319 	struct exynos_drm_manager *manager =
320 		to_exynos_encoder(encoder)->manager;
321 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
322 	int crtc = *(int *)data;
323 
324 	if (manager->pipe == -1)
325 		manager->pipe = crtc;
326 
327 	if (manager_ops->disable_vblank)
328 		manager_ops->disable_vblank(manager->dev);
329 }
330 
exynos_drm_encoder_crtc_plane_commit(struct drm_encoder * encoder,void * data)331 void exynos_drm_encoder_crtc_plane_commit(struct drm_encoder *encoder,
332 					  void *data)
333 {
334 	struct exynos_drm_manager *manager =
335 		to_exynos_encoder(encoder)->manager;
336 	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
337 	int zpos = DEFAULT_ZPOS;
338 
339 	if (data)
340 		zpos = *(int *)data;
341 
342 	if (overlay_ops && overlay_ops->commit)
343 		overlay_ops->commit(manager->dev, zpos);
344 }
345 
exynos_drm_encoder_crtc_commit(struct drm_encoder * encoder,void * data)346 void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data)
347 {
348 	struct exynos_drm_manager *manager =
349 		to_exynos_encoder(encoder)->manager;
350 	int crtc = *(int *)data;
351 	int zpos = DEFAULT_ZPOS;
352 
353 	DRM_DEBUG_KMS("%s\n", __FILE__);
354 
355 	/*
356 	 * when crtc is detached from encoder, this pipe is used
357 	 * to select manager operation
358 	 */
359 	manager->pipe = crtc;
360 
361 	exynos_drm_encoder_crtc_plane_commit(encoder, &zpos);
362 }
363 
exynos_drm_encoder_dpms_from_crtc(struct drm_encoder * encoder,void * data)364 void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder, void *data)
365 {
366 	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
367 	int mode = *(int *)data;
368 
369 	DRM_DEBUG_KMS("%s\n", __FILE__);
370 
371 	exynos_drm_encoder_dpms(encoder, mode);
372 
373 	exynos_encoder->dpms = mode;
374 }
375 
exynos_drm_encoder_crtc_dpms(struct drm_encoder * encoder,void * data)376 void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
377 {
378 	struct drm_device *dev = encoder->dev;
379 	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
380 	struct exynos_drm_manager *manager = exynos_encoder->manager;
381 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
382 	struct drm_connector *connector;
383 	int mode = *(int *)data;
384 
385 	DRM_DEBUG_KMS("%s\n", __FILE__);
386 
387 	if (manager_ops && manager_ops->dpms)
388 		manager_ops->dpms(manager->dev, mode);
389 
390 	/*
391 	 * set current dpms mode to the connector connected to
392 	 * current encoder. connector->dpms would be checked
393 	 * at drm_helper_connector_dpms()
394 	 */
395 	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
396 		if (connector->encoder == encoder)
397 			connector->dpms = mode;
398 
399 	/*
400 	 * if this condition is ok then it means that the crtc is already
401 	 * detached from encoder and last function for detaching is properly
402 	 * done, so clear pipe from manager to prevent repeated call.
403 	 */
404 	if (mode > DRM_MODE_DPMS_ON) {
405 		if (!encoder->crtc)
406 			manager->pipe = -1;
407 	}
408 }
409 
exynos_drm_encoder_crtc_mode_set(struct drm_encoder * encoder,void * data)410 void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data)
411 {
412 	struct exynos_drm_manager *manager =
413 		to_exynos_encoder(encoder)->manager;
414 	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
415 	struct exynos_drm_overlay *overlay = data;
416 
417 	if (overlay_ops && overlay_ops->mode_set)
418 		overlay_ops->mode_set(manager->dev, overlay);
419 }
420 
exynos_drm_encoder_crtc_disable(struct drm_encoder * encoder,void * data)421 void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data)
422 {
423 	struct exynos_drm_manager *manager =
424 		to_exynos_encoder(encoder)->manager;
425 	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
426 	int zpos = DEFAULT_ZPOS;
427 
428 	DRM_DEBUG_KMS("\n");
429 
430 	if (data)
431 		zpos = *(int *)data;
432 
433 	if (overlay_ops && overlay_ops->disable)
434 		overlay_ops->disable(manager->dev, zpos);
435 }
436 
437 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
438 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
439 MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
440 MODULE_DESCRIPTION("Samsung SoC DRM Encoder Driver");
441 MODULE_LICENSE("GPL");
442