]> rtime.felk.cvut.cz Git - can-eth-gw-linux.git/blob - drivers/gpu/drm/exynos/exynos_drm_encoder.c
ARM: mxs_defconfig: Improve USB related support
[can-eth-gw-linux.git] / drivers / gpu / drm / exynos / exynos_drm_encoder.c
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 <drm/drmP.h>
30 #include <drm/drm_crtc_helper.h>
31
32 #include "exynos_drm_drv.h"
33 #include "exynos_drm_encoder.h"
34 #include "exynos_drm_connector.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_crtc                 *old_crtc;
49         struct drm_encoder              drm_encoder;
50         struct exynos_drm_manager       *manager;
51         int dpms;
52 };
53
54 static void exynos_drm_connector_power(struct drm_encoder *encoder, int mode)
55 {
56         struct drm_device *dev = encoder->dev;
57         struct drm_connector *connector;
58
59         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
60                 if (exynos_drm_best_encoder(connector) == encoder) {
61                         DRM_DEBUG_KMS("connector[%d] dpms[%d]\n",
62                                         connector->base.id, mode);
63
64                         exynos_drm_display_power(connector, mode);
65                 }
66         }
67 }
68
69 static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
70 {
71         struct drm_device *dev = encoder->dev;
72         struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
73         struct exynos_drm_manager_ops *manager_ops = manager->ops;
74         struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
75
76         DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode);
77
78         if (exynos_encoder->dpms == mode) {
79                 DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
80                 return;
81         }
82
83         mutex_lock(&dev->struct_mutex);
84
85         switch (mode) {
86         case DRM_MODE_DPMS_ON:
87                 if (manager_ops && manager_ops->apply)
88                         manager_ops->apply(manager->dev);
89                 exynos_drm_connector_power(encoder, mode);
90                 exynos_encoder->dpms = mode;
91                 break;
92         case DRM_MODE_DPMS_STANDBY:
93         case DRM_MODE_DPMS_SUSPEND:
94         case DRM_MODE_DPMS_OFF:
95                 exynos_drm_connector_power(encoder, mode);
96                 exynos_encoder->dpms = mode;
97                 break;
98         default:
99                 DRM_ERROR("unspecified mode %d\n", mode);
100                 break;
101         }
102
103         mutex_unlock(&dev->struct_mutex);
104 }
105
106 static bool
107 exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
108                                const struct drm_display_mode *mode,
109                                struct drm_display_mode *adjusted_mode)
110 {
111         struct drm_device *dev = encoder->dev;
112         struct drm_connector *connector;
113         struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
114         struct exynos_drm_manager_ops *manager_ops = manager->ops;
115
116         DRM_DEBUG_KMS("%s\n", __FILE__);
117
118         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
119                 if (connector->encoder == encoder)
120                         if (manager_ops && manager_ops->mode_fixup)
121                                 manager_ops->mode_fixup(manager->dev, connector,
122                                                         mode, adjusted_mode);
123         }
124
125         return true;
126 }
127
128 static void disable_plane_to_crtc(struct drm_device *dev,
129                                                 struct drm_crtc *old_crtc,
130                                                 struct drm_crtc *new_crtc)
131 {
132         struct drm_plane *plane;
133
134         /*
135          * if old_crtc isn't same as encoder->crtc then it means that
136          * user changed crtc id to another one so the plane to old_crtc
137          * should be disabled and plane->crtc should be set to new_crtc
138          * (encoder->crtc)
139          */
140         list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
141                 if (plane->crtc == old_crtc) {
142                         /*
143                          * do not change below call order.
144                          *
145                          * plane->funcs->disable_plane call checks
146                          * if encoder->crtc is same as plane->crtc and if same
147                          * then overlay_ops->disable callback will be called
148                          * to diasble current hw overlay so plane->crtc should
149                          * have new_crtc because new_crtc was set to
150                          * encoder->crtc in advance.
151                          */
152                         plane->crtc = new_crtc;
153                         plane->funcs->disable_plane(plane);
154                 }
155         }
156 }
157
158 static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
159                                          struct drm_display_mode *mode,
160                                          struct drm_display_mode *adjusted_mode)
161 {
162         struct drm_device *dev = encoder->dev;
163         struct drm_connector *connector;
164         struct exynos_drm_manager *manager;
165         struct exynos_drm_manager_ops *manager_ops;
166
167         DRM_DEBUG_KMS("%s\n", __FILE__);
168
169         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
170                 if (connector->encoder == encoder) {
171                         struct exynos_drm_encoder *exynos_encoder;
172
173                         exynos_encoder = to_exynos_encoder(encoder);
174
175                         if (exynos_encoder->old_crtc != encoder->crtc &&
176                                         exynos_encoder->old_crtc) {
177
178                                 /*
179                                  * disable a plane to old crtc and change
180                                  * crtc of the plane to new one.
181                                  */
182                                 disable_plane_to_crtc(dev,
183                                                 exynos_encoder->old_crtc,
184                                                 encoder->crtc);
185                         }
186
187                         manager = exynos_drm_get_manager(encoder);
188                         manager_ops = manager->ops;
189
190                         if (manager_ops && manager_ops->mode_set)
191                                 manager_ops->mode_set(manager->dev,
192                                                         adjusted_mode);
193
194                         exynos_encoder->old_crtc = encoder->crtc;
195                 }
196         }
197 }
198
199 static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
200 {
201         DRM_DEBUG_KMS("%s\n", __FILE__);
202
203         /* drm framework doesn't check NULL. */
204 }
205
206 static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
207 {
208         struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
209         struct exynos_drm_manager_ops *manager_ops = manager->ops;
210
211         DRM_DEBUG_KMS("%s\n", __FILE__);
212
213         if (manager_ops && manager_ops->commit)
214                 manager_ops->commit(manager->dev);
215 }
216
217 static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
218 {
219         struct drm_plane *plane;
220         struct drm_device *dev = encoder->dev;
221
222         exynos_drm_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
223
224         /* all planes connected to this encoder should be also disabled. */
225         list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
226                 if (plane->crtc == encoder->crtc)
227                         plane->funcs->disable_plane(plane);
228         }
229 }
230
231 static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
232         .dpms           = exynos_drm_encoder_dpms,
233         .mode_fixup     = exynos_drm_encoder_mode_fixup,
234         .mode_set       = exynos_drm_encoder_mode_set,
235         .prepare        = exynos_drm_encoder_prepare,
236         .commit         = exynos_drm_encoder_commit,
237         .disable        = exynos_drm_encoder_disable,
238 };
239
240 static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
241 {
242         struct exynos_drm_encoder *exynos_encoder =
243                 to_exynos_encoder(encoder);
244
245         DRM_DEBUG_KMS("%s\n", __FILE__);
246
247         exynos_encoder->manager->pipe = -1;
248
249         drm_encoder_cleanup(encoder);
250         kfree(exynos_encoder);
251 }
252
253 static struct drm_encoder_funcs exynos_encoder_funcs = {
254         .destroy = exynos_drm_encoder_destroy,
255 };
256
257 static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
258 {
259         struct drm_encoder *clone;
260         struct drm_device *dev = encoder->dev;
261         struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
262         struct exynos_drm_display_ops *display_ops =
263                                 exynos_encoder->manager->display_ops;
264         unsigned int clone_mask = 0;
265         int cnt = 0;
266
267         list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
268                 switch (display_ops->type) {
269                 case EXYNOS_DISPLAY_TYPE_LCD:
270                 case EXYNOS_DISPLAY_TYPE_HDMI:
271                 case EXYNOS_DISPLAY_TYPE_VIDI:
272                         clone_mask |= (1 << (cnt++));
273                         break;
274                 default:
275                         continue;
276                 }
277         }
278
279         return clone_mask;
280 }
281
282 void exynos_drm_encoder_setup(struct drm_device *dev)
283 {
284         struct drm_encoder *encoder;
285
286         DRM_DEBUG_KMS("%s\n", __FILE__);
287
288         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
289                 encoder->possible_clones = exynos_drm_encoder_clones(encoder);
290 }
291
292 struct drm_encoder *
293 exynos_drm_encoder_create(struct drm_device *dev,
294                            struct exynos_drm_manager *manager,
295                            unsigned int possible_crtcs)
296 {
297         struct drm_encoder *encoder;
298         struct exynos_drm_encoder *exynos_encoder;
299
300         DRM_DEBUG_KMS("%s\n", __FILE__);
301
302         if (!manager || !possible_crtcs)
303                 return NULL;
304
305         if (!manager->dev)
306                 return NULL;
307
308         exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
309         if (!exynos_encoder) {
310                 DRM_ERROR("failed to allocate encoder\n");
311                 return NULL;
312         }
313
314         exynos_encoder->dpms = DRM_MODE_DPMS_OFF;
315         exynos_encoder->manager = manager;
316         encoder = &exynos_encoder->drm_encoder;
317         encoder->possible_crtcs = possible_crtcs;
318
319         DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
320
321         drm_encoder_init(dev, encoder, &exynos_encoder_funcs,
322                         DRM_MODE_ENCODER_TMDS);
323
324         drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
325
326         DRM_DEBUG_KMS("encoder has been created\n");
327
328         return encoder;
329 }
330
331 struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder)
332 {
333         return to_exynos_encoder(encoder)->manager;
334 }
335
336 void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
337                             void (*fn)(struct drm_encoder *, void *))
338 {
339         struct drm_device *dev = crtc->dev;
340         struct drm_encoder *encoder;
341         struct exynos_drm_private *private = dev->dev_private;
342         struct exynos_drm_manager *manager;
343
344         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
345                 /*
346                  * if crtc is detached from encoder, check pipe,
347                  * otherwise check crtc attached to encoder
348                  */
349                 if (!encoder->crtc) {
350                         manager = to_exynos_encoder(encoder)->manager;
351                         if (manager->pipe < 0 ||
352                                         private->crtc[manager->pipe] != crtc)
353                                 continue;
354                 } else {
355                         if (encoder->crtc != crtc)
356                                 continue;
357                 }
358
359                 fn(encoder, data);
360         }
361 }
362
363 void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data)
364 {
365         struct exynos_drm_manager *manager =
366                 to_exynos_encoder(encoder)->manager;
367         struct exynos_drm_manager_ops *manager_ops = manager->ops;
368         int crtc = *(int *)data;
369
370         if (manager->pipe != crtc)
371                 return;
372
373         if (manager_ops->enable_vblank)
374                 manager_ops->enable_vblank(manager->dev);
375 }
376
377 void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
378 {
379         struct exynos_drm_manager *manager =
380                 to_exynos_encoder(encoder)->manager;
381         struct exynos_drm_manager_ops *manager_ops = manager->ops;
382         int crtc = *(int *)data;
383
384         if (manager->pipe != crtc)
385                 return;
386
387         if (manager_ops->disable_vblank)
388                 manager_ops->disable_vblank(manager->dev);
389 }
390
391 void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
392 {
393         struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
394         struct exynos_drm_manager *manager = exynos_encoder->manager;
395         struct exynos_drm_manager_ops *manager_ops = manager->ops;
396         int mode = *(int *)data;
397
398         DRM_DEBUG_KMS("%s\n", __FILE__);
399
400         if (manager_ops && manager_ops->dpms)
401                 manager_ops->dpms(manager->dev, mode);
402
403         /*
404          * set current mode to new one so that data aren't updated into
405          * registers by drm_helper_connector_dpms two times.
406          *
407          * in case that drm_crtc_helper_set_mode() is called,
408          * overlay_ops->commit() and manager_ops->commit() callbacks
409          * can be called two times, first at drm_crtc_helper_set_mode()
410          * and second at drm_helper_connector_dpms().
411          * so with this setting, when drm_helper_connector_dpms() is called
412          * encoder->funcs->dpms() will be ignored.
413          */
414         exynos_encoder->dpms = mode;
415
416         /*
417          * if this condition is ok then it means that the crtc is already
418          * detached from encoder and last function for detaching is properly
419          * done, so clear pipe from manager to prevent repeated call.
420          */
421         if (mode > DRM_MODE_DPMS_ON) {
422                 if (!encoder->crtc)
423                         manager->pipe = -1;
424         }
425 }
426
427 void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data)
428 {
429         struct exynos_drm_manager *manager =
430                 to_exynos_encoder(encoder)->manager;
431         int pipe = *(int *)data;
432
433         DRM_DEBUG_KMS("%s\n", __FILE__);
434
435         /*
436          * when crtc is detached from encoder, this pipe is used
437          * to select manager operation
438          */
439         manager->pipe = pipe;
440 }
441
442 void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
443 {
444         struct exynos_drm_manager *manager =
445                 to_exynos_encoder(encoder)->manager;
446         struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
447         struct exynos_drm_overlay *overlay = data;
448
449         DRM_DEBUG_KMS("%s\n", __FILE__);
450
451         if (overlay_ops && overlay_ops->mode_set)
452                 overlay_ops->mode_set(manager->dev, overlay);
453 }
454
455 void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
456 {
457         struct exynos_drm_manager *manager =
458                 to_exynos_encoder(encoder)->manager;
459         struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
460         int zpos = DEFAULT_ZPOS;
461
462         DRM_DEBUG_KMS("%s\n", __FILE__);
463
464         if (data)
465                 zpos = *(int *)data;
466
467         if (overlay_ops && overlay_ops->commit)
468                 overlay_ops->commit(manager->dev, zpos);
469 }
470
471 void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
472 {
473         struct exynos_drm_manager *manager =
474                 to_exynos_encoder(encoder)->manager;
475         struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
476         int zpos = DEFAULT_ZPOS;
477
478         DRM_DEBUG_KMS("%s\n", __FILE__);
479
480         if (data)
481                 zpos = *(int *)data;
482
483         if (overlay_ops && overlay_ops->enable)
484                 overlay_ops->enable(manager->dev, zpos);
485 }
486
487 void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
488 {
489         struct exynos_drm_manager *manager =
490                 to_exynos_encoder(encoder)->manager;
491         struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
492         int zpos = DEFAULT_ZPOS;
493
494         DRM_DEBUG_KMS("%s\n", __FILE__);
495
496         if (data)
497                 zpos = *(int *)data;
498
499         if (overlay_ops && overlay_ops->disable)
500                 overlay_ops->disable(manager->dev, zpos);
501
502         /*
503          * wait for vblank interrupt
504          * - this makes sure that hardware overlay is disabled to avoid
505          * for the dma accesses to memory after gem buffer was released
506          * because the setting for disabling the overlay will be updated
507          * at vsync.
508          */
509         if (overlay_ops->wait_for_vblank)
510                 overlay_ops->wait_for_vblank(manager->dev);
511 }