ab3c6d41f5d9ddbbe0a1a788227a6316c5d035ca
[deliverable/linux.git] / drivers / gpu / drm / exynos / exynos_drm_connector.c
1 /*
2 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
3 * Authors:
4 * Inki Dae <inki.dae@samsung.com>
5 * Joonyoung Shim <jy0922.shim@samsung.com>
6 * Seung-Woo Kim <sw0312.kim@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14 #include <drm/drmP.h>
15 #include <drm/drm_crtc_helper.h>
16
17 #include <drm/exynos_drm.h>
18 #include "exynos_drm_drv.h"
19 #include "exynos_drm_encoder.h"
20
21 #define to_exynos_connector(x) container_of(x, struct exynos_drm_connector,\
22 drm_connector)
23
24 struct exynos_drm_connector {
25 struct drm_connector drm_connector;
26 uint32_t encoder_id;
27 struct exynos_drm_manager *manager;
28 uint32_t dpms;
29 };
30
31 /* convert exynos_video_timings to drm_display_mode */
32 static inline void
33 convert_to_display_mode(struct drm_display_mode *mode,
34 struct exynos_drm_panel_info *panel)
35 {
36 struct fb_videomode *timing = &panel->timing;
37 DRM_DEBUG_KMS("%s\n", __FILE__);
38
39 mode->clock = timing->pixclock / 1000;
40 mode->vrefresh = timing->refresh;
41
42 mode->hdisplay = timing->xres;
43 mode->hsync_start = mode->hdisplay + timing->right_margin;
44 mode->hsync_end = mode->hsync_start + timing->hsync_len;
45 mode->htotal = mode->hsync_end + timing->left_margin;
46
47 mode->vdisplay = timing->yres;
48 mode->vsync_start = mode->vdisplay + timing->lower_margin;
49 mode->vsync_end = mode->vsync_start + timing->vsync_len;
50 mode->vtotal = mode->vsync_end + timing->upper_margin;
51 mode->width_mm = panel->width_mm;
52 mode->height_mm = panel->height_mm;
53
54 if (timing->vmode & FB_VMODE_INTERLACED)
55 mode->flags |= DRM_MODE_FLAG_INTERLACE;
56
57 if (timing->vmode & FB_VMODE_DOUBLE)
58 mode->flags |= DRM_MODE_FLAG_DBLSCAN;
59 }
60
61 static int exynos_drm_connector_get_modes(struct drm_connector *connector)
62 {
63 struct exynos_drm_connector *exynos_connector =
64 to_exynos_connector(connector);
65 struct exynos_drm_manager *manager = exynos_connector->manager;
66 struct exynos_drm_display_ops *display_ops = manager->display_ops;
67 struct edid *edid = NULL;
68 unsigned int count = 0;
69 int ret;
70
71 DRM_DEBUG_KMS("%s\n", __FILE__);
72
73 if (!display_ops) {
74 DRM_DEBUG_KMS("display_ops is null.\n");
75 return 0;
76 }
77
78 /*
79 * if get_edid() exists then get_edid() callback of hdmi side
80 * is called to get edid data through i2c interface else
81 * get timing from the FIMD driver(display controller).
82 *
83 * P.S. in case of lcd panel, count is always 1 if success
84 * because lcd panel has only one mode.
85 */
86 if (display_ops->get_edid) {
87 edid = display_ops->get_edid(manager->dev, connector);
88 if (IS_ERR_OR_NULL(edid)) {
89 ret = PTR_ERR(edid);
90 edid = NULL;
91 DRM_ERROR("Panel operation get_edid failed %d\n", ret);
92 goto out;
93 }
94
95 count = drm_add_edid_modes(connector, edid);
96 if (!count) {
97 DRM_ERROR("Add edid modes failed %d\n", count);
98 goto out;
99 }
100
101 drm_mode_connector_update_edid_property(connector, edid);
102 } else {
103 struct exynos_drm_panel_info *panel;
104 struct drm_display_mode *mode = drm_mode_create(connector->dev);
105 if (!mode) {
106 DRM_ERROR("failed to create a new display mode.\n");
107 return 0;
108 }
109
110 if (display_ops->get_panel)
111 panel = display_ops->get_panel(manager->dev);
112 else {
113 drm_mode_destroy(connector->dev, mode);
114 return 0;
115 }
116
117 convert_to_display_mode(mode, panel);
118 connector->display_info.width_mm = mode->width_mm;
119 connector->display_info.height_mm = mode->height_mm;
120
121 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
122 drm_mode_set_name(mode);
123 drm_mode_probed_add(connector, mode);
124
125 count = 1;
126 }
127
128 out:
129 kfree(edid);
130 return count;
131 }
132
133 static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
134 struct drm_display_mode *mode)
135 {
136 struct exynos_drm_connector *exynos_connector =
137 to_exynos_connector(connector);
138 struct exynos_drm_manager *manager = exynos_connector->manager;
139 struct exynos_drm_display_ops *display_ops = manager->display_ops;
140 int ret = MODE_BAD;
141
142 DRM_DEBUG_KMS("%s\n", __FILE__);
143
144 if (display_ops && display_ops->check_mode)
145 if (!display_ops->check_mode(manager->dev, mode))
146 ret = MODE_OK;
147
148 return ret;
149 }
150
151 struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector)
152 {
153 struct drm_device *dev = connector->dev;
154 struct exynos_drm_connector *exynos_connector =
155 to_exynos_connector(connector);
156 struct drm_mode_object *obj;
157 struct drm_encoder *encoder;
158
159 DRM_DEBUG_KMS("%s\n", __FILE__);
160
161 obj = drm_mode_object_find(dev, exynos_connector->encoder_id,
162 DRM_MODE_OBJECT_ENCODER);
163 if (!obj) {
164 DRM_DEBUG_KMS("Unknown ENCODER ID %d\n",
165 exynos_connector->encoder_id);
166 return NULL;
167 }
168
169 encoder = obj_to_encoder(obj);
170
171 return encoder;
172 }
173
174 static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
175 .get_modes = exynos_drm_connector_get_modes,
176 .mode_valid = exynos_drm_connector_mode_valid,
177 .best_encoder = exynos_drm_best_encoder,
178 };
179
180 void exynos_drm_display_power(struct drm_connector *connector, int mode)
181 {
182 struct drm_encoder *encoder = exynos_drm_best_encoder(connector);
183 struct exynos_drm_connector *exynos_connector;
184 struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
185 struct exynos_drm_display_ops *display_ops = manager->display_ops;
186
187 exynos_connector = to_exynos_connector(connector);
188
189 if (exynos_connector->dpms == mode) {
190 DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
191 return;
192 }
193
194 if (display_ops && display_ops->power_on)
195 display_ops->power_on(manager->dev, mode);
196
197 exynos_connector->dpms = mode;
198 }
199
200 static void exynos_drm_connector_dpms(struct drm_connector *connector,
201 int mode)
202 {
203 DRM_DEBUG_KMS("%s\n", __FILE__);
204
205 /*
206 * in case that drm_crtc_helper_set_mode() is called,
207 * encoder/crtc->funcs->dpms() will be just returned
208 * because they already were DRM_MODE_DPMS_ON so only
209 * exynos_drm_display_power() will be called.
210 */
211 drm_helper_connector_dpms(connector, mode);
212
213 exynos_drm_display_power(connector, mode);
214
215 }
216
217 static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
218 unsigned int max_width, unsigned int max_height)
219 {
220 struct exynos_drm_connector *exynos_connector =
221 to_exynos_connector(connector);
222 struct exynos_drm_manager *manager = exynos_connector->manager;
223 struct exynos_drm_manager_ops *ops = manager->ops;
224 unsigned int width, height;
225
226 width = max_width;
227 height = max_height;
228
229 /*
230 * if specific driver want to find desired_mode using maxmum
231 * resolution then get max width and height from that driver.
232 */
233 if (ops && ops->get_max_resol)
234 ops->get_max_resol(manager->dev, &width, &height);
235
236 return drm_helper_probe_single_connector_modes(connector, width,
237 height);
238 }
239
240 /* get detection status of display device. */
241 static enum drm_connector_status
242 exynos_drm_connector_detect(struct drm_connector *connector, bool force)
243 {
244 struct exynos_drm_connector *exynos_connector =
245 to_exynos_connector(connector);
246 struct exynos_drm_manager *manager = exynos_connector->manager;
247 struct exynos_drm_display_ops *display_ops =
248 manager->display_ops;
249 enum drm_connector_status status = connector_status_disconnected;
250
251 DRM_DEBUG_KMS("%s\n", __FILE__);
252
253 if (display_ops && display_ops->is_connected) {
254 if (display_ops->is_connected(manager->dev))
255 status = connector_status_connected;
256 else
257 status = connector_status_disconnected;
258 }
259
260 return status;
261 }
262
263 static void exynos_drm_connector_destroy(struct drm_connector *connector)
264 {
265 struct exynos_drm_connector *exynos_connector =
266 to_exynos_connector(connector);
267
268 DRM_DEBUG_KMS("%s\n", __FILE__);
269
270 drm_sysfs_connector_remove(connector);
271 drm_connector_cleanup(connector);
272 kfree(exynos_connector);
273 }
274
275 static struct drm_connector_funcs exynos_connector_funcs = {
276 .dpms = exynos_drm_connector_dpms,
277 .fill_modes = exynos_drm_connector_fill_modes,
278 .detect = exynos_drm_connector_detect,
279 .destroy = exynos_drm_connector_destroy,
280 };
281
282 struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
283 struct drm_encoder *encoder)
284 {
285 struct exynos_drm_connector *exynos_connector;
286 struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
287 struct drm_connector *connector;
288 int type;
289 int err;
290
291 DRM_DEBUG_KMS("%s\n", __FILE__);
292
293 exynos_connector = kzalloc(sizeof(*exynos_connector), GFP_KERNEL);
294 if (!exynos_connector) {
295 DRM_ERROR("failed to allocate connector\n");
296 return NULL;
297 }
298
299 connector = &exynos_connector->drm_connector;
300
301 switch (manager->display_ops->type) {
302 case EXYNOS_DISPLAY_TYPE_HDMI:
303 type = DRM_MODE_CONNECTOR_HDMIA;
304 connector->interlace_allowed = true;
305 connector->polled = DRM_CONNECTOR_POLL_HPD;
306 break;
307 case EXYNOS_DISPLAY_TYPE_VIDI:
308 type = DRM_MODE_CONNECTOR_VIRTUAL;
309 connector->polled = DRM_CONNECTOR_POLL_HPD;
310 break;
311 default:
312 type = DRM_MODE_CONNECTOR_Unknown;
313 break;
314 }
315
316 drm_connector_init(dev, connector, &exynos_connector_funcs, type);
317 drm_connector_helper_add(connector, &exynos_connector_helper_funcs);
318
319 err = drm_sysfs_connector_add(connector);
320 if (err)
321 goto err_connector;
322
323 exynos_connector->encoder_id = encoder->base.id;
324 exynos_connector->manager = manager;
325 exynos_connector->dpms = DRM_MODE_DPMS_OFF;
326 connector->dpms = DRM_MODE_DPMS_OFF;
327 connector->encoder = encoder;
328
329 err = drm_mode_connector_attach_encoder(connector, encoder);
330 if (err) {
331 DRM_ERROR("failed to attach a connector to a encoder\n");
332 goto err_sysfs;
333 }
334
335 DRM_DEBUG_KMS("connector has been created\n");
336
337 return connector;
338
339 err_sysfs:
340 drm_sysfs_connector_remove(connector);
341 err_connector:
342 drm_connector_cleanup(connector);
343 kfree(exynos_connector);
344 return NULL;
345 }
This page took 0.037792 seconds and 4 git commands to generate.