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 */
47struct exynos_drm_encoder {
48	struct drm_encoder		drm_encoder;
49	struct exynos_drm_manager	*manager;
50	int dpms;
51};
52
53static 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
72static 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
109static bool
110exynos_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
131static 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
157static 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
164static 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
175static struct drm_crtc *
176exynos_drm_encoder_get_crtc(struct drm_encoder *encoder)
177{
178	return encoder->crtc;
179}
180
181static 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
190static 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
203static struct drm_encoder_funcs exynos_encoder_funcs = {
204	.destroy = exynos_drm_encoder_destroy,
205};
206
207static 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
232void 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
242struct drm_encoder *
243exynos_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
281struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder)
282{
283	return to_exynos_encoder(encoder)->manager;
284}
285
286void 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
313void 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
327void 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
341void 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
356void 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
374void 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
386void 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
420void 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
431void 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