Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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_encoder_helper_funcs exynos_encoder_helper_funcs = {
176	.dpms		= exynos_drm_encoder_dpms,
177	.mode_fixup	= exynos_drm_encoder_mode_fixup,
178	.mode_set	= exynos_drm_encoder_mode_set,
179	.prepare	= exynos_drm_encoder_prepare,
180	.commit		= exynos_drm_encoder_commit,
181};
182
183static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
184{
185	struct exynos_drm_encoder *exynos_encoder =
186		to_exynos_encoder(encoder);
187
188	DRM_DEBUG_KMS("%s\n", __FILE__);
189
190	exynos_encoder->manager->pipe = -1;
191
192	drm_encoder_cleanup(encoder);
193	kfree(exynos_encoder);
194}
195
196static struct drm_encoder_funcs exynos_encoder_funcs = {
197	.destroy = exynos_drm_encoder_destroy,
198};
199
200static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
201{
202	struct drm_encoder *clone;
203	struct drm_device *dev = encoder->dev;
204	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
205	struct exynos_drm_display_ops *display_ops =
206				exynos_encoder->manager->display_ops;
207	unsigned int clone_mask = 0;
208	int cnt = 0;
209
210	list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
211		switch (display_ops->type) {
212		case EXYNOS_DISPLAY_TYPE_LCD:
213		case EXYNOS_DISPLAY_TYPE_HDMI:
214		case EXYNOS_DISPLAY_TYPE_VIDI:
215			clone_mask |= (1 << (cnt++));
216			break;
217		default:
218			continue;
219		}
220	}
221
222	return clone_mask;
223}
224
225void exynos_drm_encoder_setup(struct drm_device *dev)
226{
227	struct drm_encoder *encoder;
228
229	DRM_DEBUG_KMS("%s\n", __FILE__);
230
231	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
232		encoder->possible_clones = exynos_drm_encoder_clones(encoder);
233}
234
235struct drm_encoder *
236exynos_drm_encoder_create(struct drm_device *dev,
237			   struct exynos_drm_manager *manager,
238			   unsigned int possible_crtcs)
239{
240	struct drm_encoder *encoder;
241	struct exynos_drm_encoder *exynos_encoder;
242
243	DRM_DEBUG_KMS("%s\n", __FILE__);
244
245	if (!manager || !possible_crtcs)
246		return NULL;
247
248	if (!manager->dev)
249		return NULL;
250
251	exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
252	if (!exynos_encoder) {
253		DRM_ERROR("failed to allocate encoder\n");
254		return NULL;
255	}
256
257	exynos_encoder->dpms = DRM_MODE_DPMS_OFF;
258	exynos_encoder->manager = manager;
259	encoder = &exynos_encoder->drm_encoder;
260	encoder->possible_crtcs = possible_crtcs;
261
262	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
263
264	drm_encoder_init(dev, encoder, &exynos_encoder_funcs,
265			DRM_MODE_ENCODER_TMDS);
266
267	drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
268
269	DRM_DEBUG_KMS("encoder has been created\n");
270
271	return encoder;
272}
273
274struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder)
275{
276	return to_exynos_encoder(encoder)->manager;
277}
278
279void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
280			    void (*fn)(struct drm_encoder *, void *))
281{
282	struct drm_device *dev = crtc->dev;
283	struct drm_encoder *encoder;
284	struct exynos_drm_private *private = dev->dev_private;
285	struct exynos_drm_manager *manager;
286
287	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
288		/*
289		 * if crtc is detached from encoder, check pipe,
290		 * otherwise check crtc attached to encoder
291		 */
292		if (!encoder->crtc) {
293			manager = to_exynos_encoder(encoder)->manager;
294			if (manager->pipe < 0 ||
295					private->crtc[manager->pipe] != crtc)
296				continue;
297		} else {
298			if (encoder->crtc != crtc)
299				continue;
300		}
301
302		fn(encoder, data);
303	}
304}
305
306void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data)
307{
308	struct exynos_drm_manager *manager =
309		to_exynos_encoder(encoder)->manager;
310	struct exynos_drm_manager_ops *manager_ops = manager->ops;
311	int crtc = *(int *)data;
312
313	if (manager->pipe == -1)
314		manager->pipe = crtc;
315
316	if (manager_ops->enable_vblank)
317		manager_ops->enable_vblank(manager->dev);
318}
319
320void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
321{
322	struct exynos_drm_manager *manager =
323		to_exynos_encoder(encoder)->manager;
324	struct exynos_drm_manager_ops *manager_ops = manager->ops;
325	int crtc = *(int *)data;
326
327	if (manager->pipe == -1)
328		manager->pipe = crtc;
329
330	if (manager_ops->disable_vblank)
331		manager_ops->disable_vblank(manager->dev);
332}
333
334void exynos_drm_encoder_crtc_plane_commit(struct drm_encoder *encoder,
335					  void *data)
336{
337	struct exynos_drm_manager *manager =
338		to_exynos_encoder(encoder)->manager;
339	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
340	int zpos = DEFAULT_ZPOS;
341
342	if (data)
343		zpos = *(int *)data;
344
345	if (overlay_ops && overlay_ops->commit)
346		overlay_ops->commit(manager->dev, zpos);
347}
348
349void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data)
350{
351	struct exynos_drm_manager *manager =
352		to_exynos_encoder(encoder)->manager;
353	int crtc = *(int *)data;
354	int zpos = DEFAULT_ZPOS;
355
356	DRM_DEBUG_KMS("%s\n", __FILE__);
357
358	/*
359	 * when crtc is detached from encoder, this pipe is used
360	 * to select manager operation
361	 */
362	manager->pipe = crtc;
363
364	exynos_drm_encoder_crtc_plane_commit(encoder, &zpos);
365}
366
367void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder, void *data)
368{
369	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
370	int mode = *(int *)data;
371
372	DRM_DEBUG_KMS("%s\n", __FILE__);
373
374	exynos_drm_encoder_dpms(encoder, mode);
375
376	exynos_encoder->dpms = mode;
377}
378
379void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
380{
381	struct drm_device *dev = encoder->dev;
382	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
383	struct exynos_drm_manager *manager = exynos_encoder->manager;
384	struct exynos_drm_manager_ops *manager_ops = manager->ops;
385	struct drm_connector *connector;
386	int mode = *(int *)data;
387
388	DRM_DEBUG_KMS("%s\n", __FILE__);
389
390	if (manager_ops && manager_ops->dpms)
391		manager_ops->dpms(manager->dev, mode);
392
393	/*
394	 * set current dpms mode to the connector connected to
395	 * current encoder. connector->dpms would be checked
396	 * at drm_helper_connector_dpms()
397	 */
398	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
399		if (connector->encoder == encoder)
400			connector->dpms = mode;
401
402	/*
403	 * if this condition is ok then it means that the crtc is already
404	 * detached from encoder and last function for detaching is properly
405	 * done, so clear pipe from manager to prevent repeated call.
406	 */
407	if (mode > DRM_MODE_DPMS_ON) {
408		if (!encoder->crtc)
409			manager->pipe = -1;
410	}
411}
412
413void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data)
414{
415	struct exynos_drm_manager *manager =
416		to_exynos_encoder(encoder)->manager;
417	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
418	struct exynos_drm_overlay *overlay = data;
419
420	if (overlay_ops && overlay_ops->mode_set)
421		overlay_ops->mode_set(manager->dev, overlay);
422}
423
424void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data)
425{
426	struct exynos_drm_manager *manager =
427		to_exynos_encoder(encoder)->manager;
428	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
429	int zpos = DEFAULT_ZPOS;
430
431	DRM_DEBUG_KMS("\n");
432
433	if (data)
434		zpos = *(int *)data;
435
436	if (overlay_ops && overlay_ops->disable)
437		overlay_ops->disable(manager->dev, zpos);
438}