]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/exynos/exynos_drm_encoder.c
drm/exynos: Remove dpms link between encoder/connector
[karo-tx-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  * This program is free software; you can redistribute  it and/or modify it
10  * under  the terms of  the GNU General  Public License as published by the
11  * Free Software Foundation;  either version 2 of the  License, or (at your
12  * option) any later version.
13  */
14
15 #include <drm/drmP.h>
16 #include <drm/drm_crtc_helper.h>
17
18 #include "exynos_drm_drv.h"
19 #include "exynos_drm_encoder.h"
20 #include "exynos_drm_connector.h"
21
22 #define to_exynos_encoder(x)    container_of(x, struct exynos_drm_encoder,\
23                                 drm_encoder)
24
25 /*
26  * exynos specific encoder structure.
27  *
28  * @drm_encoder: encoder object.
29  * @manager: specific encoder has its own manager to control a hardware
30  *      appropriately and we can access a hardware drawing on this manager.
31  * @dpms: store the encoder dpms value.
32  */
33 struct exynos_drm_encoder {
34         struct drm_crtc                 *old_crtc;
35         struct drm_encoder              drm_encoder;
36         struct exynos_drm_manager       *manager;
37         int                             dpms;
38 };
39
40 static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
41 {
42         struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
43         struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
44         struct exynos_drm_display_ops *display_ops = manager->display_ops;
45
46         DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
47
48         if (exynos_encoder->dpms == mode) {
49                 DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
50                 return;
51         }
52
53         if (display_ops && display_ops->power_on)
54                 display_ops->power_on(manager->ctx, mode);
55
56         exynos_encoder->dpms = mode;
57 }
58
59 static bool
60 exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
61                                const struct drm_display_mode *mode,
62                                struct drm_display_mode *adjusted_mode)
63 {
64         struct drm_device *dev = encoder->dev;
65         struct drm_connector *connector;
66         struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
67         struct exynos_drm_manager_ops *manager_ops = manager->ops;
68
69         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
70                 if (connector->encoder == encoder)
71                         if (manager_ops && manager_ops->mode_fixup)
72                                 manager_ops->mode_fixup(manager, connector,
73                                                         mode, adjusted_mode);
74         }
75
76         return true;
77 }
78
79 static void disable_plane_to_crtc(struct drm_device *dev,
80                                                 struct drm_crtc *old_crtc,
81                                                 struct drm_crtc *new_crtc)
82 {
83         struct drm_plane *plane;
84
85         /*
86          * if old_crtc isn't same as encoder->crtc then it means that
87          * user changed crtc id to another one so the plane to old_crtc
88          * should be disabled and plane->crtc should be set to new_crtc
89          * (encoder->crtc)
90          */
91         list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
92                 if (plane->crtc == old_crtc) {
93                         /*
94                          * do not change below call order.
95                          *
96                          * plane->funcs->disable_plane call checks
97                          * if encoder->crtc is same as plane->crtc and if same
98                          * then manager_ops->win_disable callback will be called
99                          * to diasble current hw overlay so plane->crtc should
100                          * have new_crtc because new_crtc was set to
101                          * encoder->crtc in advance.
102                          */
103                         plane->crtc = new_crtc;
104                         plane->funcs->disable_plane(plane);
105                 }
106         }
107 }
108
109 static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
110                                          struct drm_display_mode *mode,
111                                          struct drm_display_mode *adjusted_mode)
112 {
113         struct drm_device *dev = encoder->dev;
114         struct drm_connector *connector;
115         struct exynos_drm_manager *manager;
116         struct exynos_drm_manager_ops *manager_ops;
117
118         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
119                 if (connector->encoder == encoder) {
120                         struct exynos_drm_encoder *exynos_encoder;
121
122                         exynos_encoder = to_exynos_encoder(encoder);
123
124                         if (exynos_encoder->old_crtc != encoder->crtc &&
125                                         exynos_encoder->old_crtc) {
126
127                                 /*
128                                  * disable a plane to old crtc and change
129                                  * crtc of the plane to new one.
130                                  */
131                                 disable_plane_to_crtc(dev,
132                                                 exynos_encoder->old_crtc,
133                                                 encoder->crtc);
134                         }
135
136                         manager = exynos_drm_get_manager(encoder);
137                         manager_ops = manager->ops;
138
139                         if (manager_ops && manager_ops->mode_set)
140                                 manager_ops->mode_set(manager, adjusted_mode);
141
142                         exynos_encoder->old_crtc = encoder->crtc;
143                 }
144         }
145 }
146
147 static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
148 {
149         /* drm framework doesn't check NULL. */
150 }
151
152 static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
153 {
154         struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
155         struct exynos_drm_manager *manager = exynos_encoder->manager;
156         struct exynos_drm_manager_ops *manager_ops = manager->ops;
157
158         if (manager_ops && manager_ops->commit)
159                 manager_ops->commit(manager);
160
161         /*
162          * In case of setcrtc, there is no way to update encoder's dpms
163          * so update it here.
164          */
165         exynos_encoder->dpms = DRM_MODE_DPMS_ON;
166 }
167
168 void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb)
169 {
170         struct exynos_drm_encoder *exynos_encoder;
171         struct exynos_drm_manager_ops *ops;
172         struct drm_device *dev = fb->dev;
173         struct drm_encoder *encoder;
174
175         /*
176          * make sure that overlay data are updated to real hardware
177          * for all encoders.
178          */
179         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
180                 exynos_encoder = to_exynos_encoder(encoder);
181                 ops = exynos_encoder->manager->ops;
182
183                 /*
184                  * wait for vblank interrupt
185                  * - this makes sure that overlay data are updated to
186                  *      real hardware.
187                  */
188                 if (ops->wait_for_vblank)
189                         ops->wait_for_vblank(exynos_encoder->manager);
190         }
191 }
192
193
194 static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
195 {
196         struct drm_plane *plane;
197         struct drm_device *dev = encoder->dev;
198
199         exynos_drm_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
200
201         /* all planes connected to this encoder should be also disabled. */
202         list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
203                 if (plane->crtc == encoder->crtc)
204                         plane->funcs->disable_plane(plane);
205         }
206 }
207
208 static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
209         .dpms           = exynos_drm_encoder_dpms,
210         .mode_fixup     = exynos_drm_encoder_mode_fixup,
211         .mode_set       = exynos_drm_encoder_mode_set,
212         .prepare        = exynos_drm_encoder_prepare,
213         .commit         = exynos_drm_encoder_commit,
214         .disable        = exynos_drm_encoder_disable,
215 };
216
217 static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
218 {
219         struct exynos_drm_encoder *exynos_encoder =
220                 to_exynos_encoder(encoder);
221
222         exynos_encoder->manager->pipe = -1;
223
224         drm_encoder_cleanup(encoder);
225         kfree(exynos_encoder);
226 }
227
228 static struct drm_encoder_funcs exynos_encoder_funcs = {
229         .destroy = exynos_drm_encoder_destroy,
230 };
231
232 static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
233 {
234         struct drm_encoder *clone;
235         struct drm_device *dev = encoder->dev;
236         struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
237         struct exynos_drm_display_ops *display_ops =
238                                 exynos_encoder->manager->display_ops;
239         unsigned int clone_mask = 0;
240         int cnt = 0;
241
242         list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
243                 switch (display_ops->type) {
244                 case EXYNOS_DISPLAY_TYPE_LCD:
245                 case EXYNOS_DISPLAY_TYPE_HDMI:
246                 case EXYNOS_DISPLAY_TYPE_VIDI:
247                         clone_mask |= (1 << (cnt++));
248                         break;
249                 default:
250                         continue;
251                 }
252         }
253
254         return clone_mask;
255 }
256
257 void exynos_drm_encoder_setup(struct drm_device *dev)
258 {
259         struct drm_encoder *encoder;
260
261         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
262                 encoder->possible_clones = exynos_drm_encoder_clones(encoder);
263 }
264
265 struct drm_encoder *
266 exynos_drm_encoder_create(struct drm_device *dev,
267                            struct exynos_drm_manager *manager,
268                            unsigned int possible_crtcs)
269 {
270         struct drm_encoder *encoder;
271         struct exynos_drm_encoder *exynos_encoder;
272         int ret;
273
274         if (!manager || !possible_crtcs)
275                 return NULL;
276
277         if (!manager->dev)
278                 return NULL;
279
280         exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
281         if (!exynos_encoder)
282                 return NULL;
283
284         exynos_encoder->dpms = DRM_MODE_DPMS_OFF;
285         exynos_encoder->manager = manager;
286         encoder = &exynos_encoder->drm_encoder;
287         encoder->possible_crtcs = possible_crtcs;
288
289         DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
290
291         drm_encoder_init(dev, encoder, &exynos_encoder_funcs,
292                         DRM_MODE_ENCODER_TMDS);
293
294         drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
295
296         if (manager->ops && manager->ops->initialize) {
297                 ret = manager->ops->initialize(manager, dev);
298                 if (ret) {
299                         DRM_ERROR("Manager initialize failed %d\n", ret);
300                         goto error;
301                 }
302         }
303
304         if (manager->display_ops && manager->display_ops->initialize) {
305                 ret = manager->display_ops->initialize(manager->dev, dev);
306                 if (ret) {
307                         DRM_ERROR("Display initialize failed %d\n", ret);
308                         goto error;
309                 }
310         }
311
312         DRM_DEBUG_KMS("encoder has been created\n");
313
314         return encoder;
315
316 error:
317         exynos_drm_encoder_destroy(&exynos_encoder->drm_encoder);
318         return NULL;
319 }
320
321 struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder)
322 {
323         return to_exynos_encoder(encoder)->manager;
324 }
325
326 void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
327                             void (*fn)(struct drm_encoder *, void *))
328 {
329         struct drm_device *dev = crtc->dev;
330         struct drm_encoder *encoder;
331         struct exynos_drm_private *private = dev->dev_private;
332         struct exynos_drm_manager *manager;
333
334         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
335                 /*
336                  * if crtc is detached from encoder, check pipe,
337                  * otherwise check crtc attached to encoder
338                  */
339                 if (!encoder->crtc) {
340                         manager = to_exynos_encoder(encoder)->manager;
341                         if (manager->pipe < 0 ||
342                                         private->crtc[manager->pipe] != crtc)
343                                 continue;
344                 } else {
345                         if (encoder->crtc != crtc)
346                                 continue;
347                 }
348
349                 fn(encoder, data);
350         }
351 }
352
353 void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data)
354 {
355         struct exynos_drm_manager *manager =
356                 to_exynos_encoder(encoder)->manager;
357         struct exynos_drm_manager_ops *manager_ops = manager->ops;
358         int crtc = *(int *)data;
359
360         if (manager->pipe != crtc)
361                 return;
362
363         if (manager_ops->enable_vblank)
364                 manager_ops->enable_vblank(manager);
365 }
366
367 void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
368 {
369         struct exynos_drm_manager *manager =
370                 to_exynos_encoder(encoder)->manager;
371         struct exynos_drm_manager_ops *manager_ops = manager->ops;
372         int crtc = *(int *)data;
373
374         if (manager->pipe != crtc)
375                 return;
376
377         if (manager_ops->disable_vblank)
378                 manager_ops->disable_vblank(manager);
379 }
380
381 void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
382 {
383         struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
384         struct exynos_drm_manager *manager = exynos_encoder->manager;
385         struct exynos_drm_manager_ops *manager_ops = manager->ops;
386         int mode = *(int *)data;
387
388         if (manager_ops && manager_ops->dpms)
389                 manager_ops->dpms(manager, mode);
390
391         /*
392          * if this condition is ok then it means that the crtc is already
393          * detached from encoder and last function for detaching is properly
394          * done, so clear pipe from manager to prevent repeated call.
395          */
396         if (mode > DRM_MODE_DPMS_ON) {
397                 if (!encoder->crtc)
398                         manager->pipe = -1;
399         }
400 }
401
402 void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data)
403 {
404         struct exynos_drm_manager *manager =
405                 to_exynos_encoder(encoder)->manager;
406         int pipe = *(int *)data;
407
408         /*
409          * when crtc is detached from encoder, this pipe is used
410          * to select manager operation
411          */
412         manager->pipe = pipe;
413 }
414
415 void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
416 {
417         struct exynos_drm_manager *manager =
418                 to_exynos_encoder(encoder)->manager;
419         struct exynos_drm_manager_ops *manager_ops = manager->ops;
420         struct exynos_drm_overlay *overlay = data;
421
422         if (manager_ops && manager_ops->win_mode_set)
423                 manager_ops->win_mode_set(manager, overlay);
424 }
425
426 void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
427 {
428         struct exynos_drm_manager *manager =
429                 to_exynos_encoder(encoder)->manager;
430         struct exynos_drm_manager_ops *manager_ops = manager->ops;
431         int zpos = DEFAULT_ZPOS;
432
433         if (data)
434                 zpos = *(int *)data;
435
436         if (manager_ops && manager_ops->win_commit)
437                 manager_ops->win_commit(manager, zpos);
438 }
439
440 void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
441 {
442         struct exynos_drm_manager *manager =
443                 to_exynos_encoder(encoder)->manager;
444         struct exynos_drm_manager_ops *manager_ops = manager->ops;
445         int zpos = DEFAULT_ZPOS;
446
447         if (data)
448                 zpos = *(int *)data;
449
450         if (manager_ops && manager_ops->win_enable)
451                 manager_ops->win_enable(manager, zpos);
452 }
453
454 void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
455 {
456         struct exynos_drm_manager *manager =
457                 to_exynos_encoder(encoder)->manager;
458         struct exynos_drm_manager_ops *manager_ops = manager->ops;
459         int zpos = DEFAULT_ZPOS;
460
461         if (data)
462                 zpos = *(int *)data;
463
464         if (manager_ops && manager_ops->win_disable)
465                 manager_ops->win_disable(manager, zpos);
466 }