]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpu/drm/omapdrm/omap_encoder.c
drm/omap: Add support for drm_bridge
[linux.git] / drivers / gpu / drm / omapdrm / omap_encoder.c
1 /*
2  * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
3  * Author: Rob Clark <rob@ti.com>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 as published by
7  * the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <linux/list.h>
19
20 #include <drm/drm_crtc.h>
21 #include <drm/drm_modeset_helper_vtables.h>
22 #include <drm/drm_edid.h>
23
24 #include "omap_drv.h"
25
26 /*
27  * encoder funcs
28  */
29
30 #define to_omap_encoder(x) container_of(x, struct omap_encoder, base)
31
32 /* The encoder and connector both map to same dssdev.. the encoder
33  * handles the 'active' parts, ie. anything the modifies the state
34  * of the hw, and the connector handles the 'read-only' parts, like
35  * detecting connection and reading edid.
36  */
37 struct omap_encoder {
38         struct drm_encoder base;
39         struct omap_dss_device *output;
40 };
41
42 static void omap_encoder_destroy(struct drm_encoder *encoder)
43 {
44         struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
45
46         drm_encoder_cleanup(encoder);
47         kfree(omap_encoder);
48 }
49
50 static const struct drm_encoder_funcs omap_encoder_funcs = {
51         .destroy = omap_encoder_destroy,
52 };
53
54 static void omap_encoder_update_videomode_flags(struct videomode *vm,
55                                                 u32 bus_flags)
56 {
57         if (!(vm->flags & (DISPLAY_FLAGS_DE_LOW |
58                            DISPLAY_FLAGS_DE_HIGH))) {
59                 if (bus_flags & DRM_BUS_FLAG_DE_LOW)
60                         vm->flags |= DISPLAY_FLAGS_DE_LOW;
61                 else if (bus_flags & DRM_BUS_FLAG_DE_HIGH)
62                         vm->flags |= DISPLAY_FLAGS_DE_HIGH;
63         }
64
65         if (!(vm->flags & (DISPLAY_FLAGS_PIXDATA_POSEDGE |
66                            DISPLAY_FLAGS_PIXDATA_NEGEDGE))) {
67                 if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
68                         vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
69                 else if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
70                         vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
71         }
72
73         if (!(vm->flags & (DISPLAY_FLAGS_SYNC_POSEDGE |
74                            DISPLAY_FLAGS_SYNC_NEGEDGE))) {
75                 if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE)
76                         vm->flags |= DISPLAY_FLAGS_SYNC_POSEDGE;
77                 else if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE)
78                         vm->flags |= DISPLAY_FLAGS_SYNC_NEGEDGE;
79         }
80 }
81
82 static void omap_encoder_hdmi_mode_set(struct drm_encoder *encoder,
83                                        struct drm_display_mode *adjusted_mode)
84 {
85         struct drm_device *dev = encoder->dev;
86         struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
87         struct omap_dss_device *dssdev = omap_encoder->output;
88         struct drm_connector *connector;
89         bool hdmi_mode;
90
91         hdmi_mode = false;
92         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
93                 if (connector->encoder == encoder) {
94                         hdmi_mode = omap_connector_get_hdmi_mode(connector);
95                         break;
96                 }
97         }
98
99         if (dssdev->ops->hdmi.set_hdmi_mode)
100                 dssdev->ops->hdmi.set_hdmi_mode(dssdev, hdmi_mode);
101
102         if (hdmi_mode && dssdev->ops->hdmi.set_infoframe) {
103                 struct hdmi_avi_infoframe avi;
104                 int r;
105
106                 r = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector,
107                                                              adjusted_mode);
108                 if (r == 0)
109                         dssdev->ops->hdmi.set_infoframe(dssdev, &avi);
110         }
111 }
112
113 static void omap_encoder_mode_set(struct drm_encoder *encoder,
114                                   struct drm_display_mode *mode,
115                                   struct drm_display_mode *adjusted_mode)
116 {
117         struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
118         struct omap_dss_device *output = omap_encoder->output;
119         struct omap_dss_device *dssdev;
120         struct drm_bridge *bridge;
121         struct videomode vm = { 0 };
122
123         drm_display_mode_to_videomode(adjusted_mode, &vm);
124
125         /*
126          * HACK: This fixes the vm flags.
127          * struct drm_display_mode does not contain the VSYNC/HSYNC/DE flags and
128          * they get lost when converting back and forth between struct
129          * drm_display_mode and struct videomode. The hack below goes and
130          * fetches the missing flags.
131          *
132          * A better solution is to use DRM's bus-flags through the whole driver.
133          */
134         for (dssdev = output; dssdev; dssdev = dssdev->next)
135                 omap_encoder_update_videomode_flags(&vm, dssdev->bus_flags);
136
137         for (bridge = output->bridge; bridge; bridge = bridge->next) {
138                 u32 bus_flags;
139
140                 if (!bridge->timings)
141                         continue;
142
143                 bus_flags = bridge->timings->input_bus_flags;
144                 omap_encoder_update_videomode_flags(&vm, bus_flags);
145         }
146
147         /* Set timings for all devices in the display pipeline. */
148         dss_mgr_set_timings(output, &vm);
149
150         for (dssdev = output; dssdev; dssdev = dssdev->next) {
151                 if (dssdev->ops->set_timings)
152                         dssdev->ops->set_timings(dssdev, adjusted_mode);
153         }
154
155         /* Set the HDMI mode and HDMI infoframe if applicable. */
156         if (output->type == OMAP_DISPLAY_TYPE_HDMI)
157                 omap_encoder_hdmi_mode_set(encoder, adjusted_mode);
158 }
159
160 static void omap_encoder_disable(struct drm_encoder *encoder)
161 {
162         struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
163         struct omap_dss_device *dssdev = omap_encoder->output;
164         struct drm_device *dev = encoder->dev;
165
166         dev_dbg(dev->dev, "disable(%s)\n", dssdev->name);
167
168         /*
169          * Disable the chain of external devices, starting at the one at the
170          * internal encoder's output.
171          */
172         omapdss_device_disable(dssdev->next);
173
174         /*
175          * Disable the internal encoder. This will disable the DSS output. The
176          * DSI is treated as an exception as DSI pipelines still use the legacy
177          * flow where the pipeline output controls the encoder.
178          */
179         if (dssdev->type != OMAP_DISPLAY_TYPE_DSI) {
180                 dssdev->ops->disable(dssdev);
181                 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
182         }
183
184         /*
185          * Perform the post-disable operations on the chain of external devices
186          * to complete the display pipeline disable.
187          */
188         omapdss_device_post_disable(dssdev->next);
189 }
190
191 static void omap_encoder_enable(struct drm_encoder *encoder)
192 {
193         struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
194         struct omap_dss_device *dssdev = omap_encoder->output;
195         struct drm_device *dev = encoder->dev;
196
197         dev_dbg(dev->dev, "enable(%s)\n", dssdev->name);
198
199         /* Prepare the chain of external devices for pipeline enable. */
200         omapdss_device_pre_enable(dssdev->next);
201
202         /*
203          * Enable the internal encoder. This will enable the DSS output. The
204          * DSI is treated as an exception as DSI pipelines still use the legacy
205          * flow where the pipeline output controls the encoder.
206          */
207         if (dssdev->type != OMAP_DISPLAY_TYPE_DSI) {
208                 dssdev->ops->enable(dssdev);
209                 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
210         }
211
212         /*
213          * Enable the chain of external devices, starting at the one at the
214          * internal encoder's output.
215          */
216         omapdss_device_enable(dssdev->next);
217 }
218
219 static int omap_encoder_atomic_check(struct drm_encoder *encoder,
220                                      struct drm_crtc_state *crtc_state,
221                                      struct drm_connector_state *conn_state)
222 {
223         struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
224         enum drm_mode_status status;
225
226         status = omap_connector_mode_fixup(omap_encoder->output,
227                                            &crtc_state->mode,
228                                            &crtc_state->adjusted_mode);
229         if (status != MODE_OK) {
230                 dev_err(encoder->dev->dev, "invalid timings: %d\n", status);
231                 return -EINVAL;
232         }
233
234         return 0;
235 }
236
237 static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {
238         .mode_set = omap_encoder_mode_set,
239         .disable = omap_encoder_disable,
240         .enable = omap_encoder_enable,
241         .atomic_check = omap_encoder_atomic_check,
242 };
243
244 /* initialize encoder */
245 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
246                                       struct omap_dss_device *output)
247 {
248         struct drm_encoder *encoder = NULL;
249         struct omap_encoder *omap_encoder;
250
251         omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL);
252         if (!omap_encoder)
253                 goto fail;
254
255         omap_encoder->output = output;
256
257         encoder = &omap_encoder->base;
258
259         drm_encoder_init(dev, encoder, &omap_encoder_funcs,
260                          DRM_MODE_ENCODER_TMDS, NULL);
261         drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs);
262
263         return encoder;
264
265 fail:
266         if (encoder)
267                 omap_encoder_destroy(encoder);
268
269         return NULL;
270 }