Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[cascardo/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
21 #define to_exynos_encoder(x)    container_of(x, struct exynos_drm_encoder,\
22                                 drm_encoder)
23
24 /*
25  * exynos specific encoder structure.
26  *
27  * @drm_encoder: encoder object.
28  * @display: the display structure that maps to this encoder
29  */
30 struct exynos_drm_encoder {
31         struct drm_encoder              drm_encoder;
32         struct exynos_drm_display       *display;
33 };
34
35 static bool
36 exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
37                                const struct drm_display_mode *mode,
38                                struct drm_display_mode *adjusted_mode)
39 {
40         struct drm_device *dev = encoder->dev;
41         struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
42         struct exynos_drm_display *display = exynos_encoder->display;
43         struct drm_connector *connector;
44
45         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
46                 if (connector->encoder != encoder)
47                         continue;
48
49                 if (display->ops->mode_fixup)
50                         display->ops->mode_fixup(display, connector, mode,
51                                         adjusted_mode);
52         }
53
54         return true;
55 }
56
57 static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
58                                          struct drm_display_mode *mode,
59                                          struct drm_display_mode *adjusted_mode)
60 {
61         struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
62         struct exynos_drm_display *display = exynos_encoder->display;
63
64         if (display->ops->mode_set)
65                 display->ops->mode_set(display, adjusted_mode);
66 }
67
68 static void exynos_drm_encoder_enable(struct drm_encoder *encoder)
69 {
70         struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
71         struct exynos_drm_display *display = exynos_encoder->display;
72
73         if (display->ops->dpms)
74                 display->ops->dpms(display, DRM_MODE_DPMS_ON);
75
76         if (display->ops->commit)
77                 display->ops->commit(display);
78 }
79
80 static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
81 {
82         struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
83         struct exynos_drm_display *display = exynos_encoder->display;
84
85         if (display->ops->dpms)
86                 display->ops->dpms(display, DRM_MODE_DPMS_OFF);
87 }
88
89 static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
90         .mode_fixup     = exynos_drm_encoder_mode_fixup,
91         .mode_set       = exynos_drm_encoder_mode_set,
92         .enable         = exynos_drm_encoder_enable,
93         .disable        = exynos_drm_encoder_disable,
94 };
95
96 static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
97 {
98         struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
99
100         drm_encoder_cleanup(encoder);
101         kfree(exynos_encoder);
102 }
103
104 static struct drm_encoder_funcs exynos_encoder_funcs = {
105         .destroy = exynos_drm_encoder_destroy,
106 };
107
108 static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
109 {
110         struct drm_encoder *clone;
111         struct drm_device *dev = encoder->dev;
112         struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
113         struct exynos_drm_display *display = exynos_encoder->display;
114         unsigned int clone_mask = 0;
115         int cnt = 0;
116
117         list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
118                 switch (display->type) {
119                 case EXYNOS_DISPLAY_TYPE_LCD:
120                 case EXYNOS_DISPLAY_TYPE_HDMI:
121                 case EXYNOS_DISPLAY_TYPE_VIDI:
122                         clone_mask |= (1 << (cnt++));
123                         break;
124                 default:
125                         continue;
126                 }
127         }
128
129         return clone_mask;
130 }
131
132 void exynos_drm_encoder_setup(struct drm_device *dev)
133 {
134         struct drm_encoder *encoder;
135
136         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
137                 encoder->possible_clones = exynos_drm_encoder_clones(encoder);
138 }
139
140 struct drm_encoder *
141 exynos_drm_encoder_create(struct drm_device *dev,
142                            struct exynos_drm_display *display,
143                            unsigned long possible_crtcs)
144 {
145         struct drm_encoder *encoder;
146         struct exynos_drm_encoder *exynos_encoder;
147
148         if (!possible_crtcs)
149                 return NULL;
150
151         exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
152         if (!exynos_encoder)
153                 return NULL;
154
155         exynos_encoder->display = display;
156         encoder = &exynos_encoder->drm_encoder;
157         encoder->possible_crtcs = possible_crtcs;
158
159         DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
160
161         drm_encoder_init(dev, encoder, &exynos_encoder_funcs,
162                         DRM_MODE_ENCODER_TMDS);
163
164         drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
165
166         DRM_DEBUG_KMS("encoder has been created\n");
167
168         return encoder;
169 }
170
171 struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder)
172 {
173         return to_exynos_encoder(encoder)->display;
174 }