]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/exynos/exynos_drm_connector.c
drm/exynos: Add missing includes
[karo-tx-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 #include "exynos_drm_connector.h"
21
22 #define to_exynos_connector(x)  container_of(x, struct exynos_drm_connector,\
23                                 drm_connector)
24
25 struct exynos_drm_connector {
26         struct drm_connector    drm_connector;
27         uint32_t                encoder_id;
28         struct exynos_drm_manager *manager;
29         uint32_t                dpms;
30 };
31
32 /* convert exynos_video_timings to drm_display_mode */
33 static inline void
34 convert_to_display_mode(struct drm_display_mode *mode,
35                         struct exynos_drm_panel_info *panel)
36 {
37         struct fb_videomode *timing = &panel->timing;
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         if (!display_ops) {
72                 DRM_DEBUG_KMS("display_ops is null.\n");
73                 return 0;
74         }
75
76         /*
77          * if get_edid() exists then get_edid() callback of hdmi side
78          * is called to get edid data through i2c interface else
79          * get timing from the FIMD driver(display controller).
80          *
81          * P.S. in case of lcd panel, count is always 1 if success
82          * because lcd panel has only one mode.
83          */
84         if (display_ops->get_edid) {
85                 edid = display_ops->get_edid(manager->dev, connector);
86                 if (IS_ERR_OR_NULL(edid)) {
87                         ret = PTR_ERR(edid);
88                         edid = NULL;
89                         DRM_ERROR("Panel operation get_edid failed %d\n", ret);
90                         goto out;
91                 }
92
93                 count = drm_add_edid_modes(connector, edid);
94                 if (!count) {
95                         DRM_ERROR("Add edid modes failed %d\n", count);
96                         goto out;
97                 }
98
99                 drm_mode_connector_update_edid_property(connector, edid);
100         } else {
101                 struct exynos_drm_panel_info *panel;
102                 struct drm_display_mode *mode = drm_mode_create(connector->dev);
103                 if (!mode) {
104                         DRM_ERROR("failed to create a new display mode.\n");
105                         return 0;
106                 }
107
108                 if (display_ops->get_panel)
109                         panel = display_ops->get_panel(manager->dev);
110                 else {
111                         drm_mode_destroy(connector->dev, mode);
112                         return 0;
113                 }
114
115                 convert_to_display_mode(mode, panel);
116                 connector->display_info.width_mm = mode->width_mm;
117                 connector->display_info.height_mm = mode->height_mm;
118
119                 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
120                 drm_mode_set_name(mode);
121                 drm_mode_probed_add(connector, mode);
122
123                 count = 1;
124         }
125
126 out:
127         kfree(edid);
128         return count;
129 }
130
131 static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
132                                             struct drm_display_mode *mode)
133 {
134         struct exynos_drm_connector *exynos_connector =
135                                         to_exynos_connector(connector);
136         struct exynos_drm_manager *manager = exynos_connector->manager;
137         struct exynos_drm_display_ops *display_ops = manager->display_ops;
138         int ret = MODE_BAD;
139
140         DRM_DEBUG_KMS("%s\n", __FILE__);
141
142         if (display_ops && display_ops->check_mode)
143                 if (!display_ops->check_mode(manager->dev, mode))
144                         ret = MODE_OK;
145
146         return ret;
147 }
148
149 struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector)
150 {
151         struct drm_device *dev = connector->dev;
152         struct exynos_drm_connector *exynos_connector =
153                                         to_exynos_connector(connector);
154         struct drm_mode_object *obj;
155         struct drm_encoder *encoder;
156
157         obj = drm_mode_object_find(dev, exynos_connector->encoder_id,
158                                    DRM_MODE_OBJECT_ENCODER);
159         if (!obj) {
160                 DRM_DEBUG_KMS("Unknown ENCODER ID %d\n",
161                                 exynos_connector->encoder_id);
162                 return NULL;
163         }
164
165         encoder = obj_to_encoder(obj);
166
167         return encoder;
168 }
169
170 static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
171         .get_modes      = exynos_drm_connector_get_modes,
172         .mode_valid     = exynos_drm_connector_mode_valid,
173         .best_encoder   = exynos_drm_best_encoder,
174 };
175
176 void exynos_drm_display_power(struct drm_connector *connector, int mode)
177 {
178         struct drm_encoder *encoder = exynos_drm_best_encoder(connector);
179         struct exynos_drm_connector *exynos_connector;
180         struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
181         struct exynos_drm_display_ops *display_ops = manager->display_ops;
182
183         exynos_connector = to_exynos_connector(connector);
184
185         if (exynos_connector->dpms == mode) {
186                 DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
187                 return;
188         }
189
190         if (display_ops && display_ops->power_on)
191                 display_ops->power_on(manager->dev, mode);
192
193         exynos_connector->dpms = mode;
194 }
195
196 static void exynos_drm_connector_dpms(struct drm_connector *connector,
197                                         int mode)
198 {
199         /*
200          * in case that drm_crtc_helper_set_mode() is called,
201          * encoder/crtc->funcs->dpms() will be just returned
202          * because they already were DRM_MODE_DPMS_ON so only
203          * exynos_drm_display_power() will be called.
204          */
205         drm_helper_connector_dpms(connector, mode);
206
207         exynos_drm_display_power(connector, mode);
208
209 }
210
211 static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
212                                 unsigned int max_width, unsigned int max_height)
213 {
214         struct exynos_drm_connector *exynos_connector =
215                                         to_exynos_connector(connector);
216         struct exynos_drm_manager *manager = exynos_connector->manager;
217         struct exynos_drm_manager_ops *ops = manager->ops;
218         unsigned int width, height;
219
220         width = max_width;
221         height = max_height;
222
223         /*
224          * if specific driver want to find desired_mode using maxmum
225          * resolution then get max width and height from that driver.
226          */
227         if (ops && ops->get_max_resol)
228                 ops->get_max_resol(manager->dev, &width, &height);
229
230         return drm_helper_probe_single_connector_modes(connector, width,
231                                                         height);
232 }
233
234 /* get detection status of display device. */
235 static enum drm_connector_status
236 exynos_drm_connector_detect(struct drm_connector *connector, bool force)
237 {
238         struct exynos_drm_connector *exynos_connector =
239                                         to_exynos_connector(connector);
240         struct exynos_drm_manager *manager = exynos_connector->manager;
241         struct exynos_drm_display_ops *display_ops =
242                                         manager->display_ops;
243         enum drm_connector_status status = connector_status_disconnected;
244
245         if (display_ops && display_ops->is_connected) {
246                 if (display_ops->is_connected(manager->dev))
247                         status = connector_status_connected;
248                 else
249                         status = connector_status_disconnected;
250         }
251
252         return status;
253 }
254
255 static void exynos_drm_connector_destroy(struct drm_connector *connector)
256 {
257         struct exynos_drm_connector *exynos_connector =
258                 to_exynos_connector(connector);
259
260         drm_sysfs_connector_remove(connector);
261         drm_connector_cleanup(connector);
262         kfree(exynos_connector);
263 }
264
265 static struct drm_connector_funcs exynos_connector_funcs = {
266         .dpms           = exynos_drm_connector_dpms,
267         .fill_modes     = exynos_drm_connector_fill_modes,
268         .detect         = exynos_drm_connector_detect,
269         .destroy        = exynos_drm_connector_destroy,
270 };
271
272 struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
273                                                    struct drm_encoder *encoder)
274 {
275         struct exynos_drm_connector *exynos_connector;
276         struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
277         struct drm_connector *connector;
278         int type;
279         int err;
280
281         exynos_connector = kzalloc(sizeof(*exynos_connector), GFP_KERNEL);
282         if (!exynos_connector) {
283                 DRM_ERROR("failed to allocate connector\n");
284                 return NULL;
285         }
286
287         connector = &exynos_connector->drm_connector;
288
289         switch (manager->display_ops->type) {
290         case EXYNOS_DISPLAY_TYPE_HDMI:
291                 type = DRM_MODE_CONNECTOR_HDMIA;
292                 connector->interlace_allowed = true;
293                 connector->polled = DRM_CONNECTOR_POLL_HPD;
294                 break;
295         case EXYNOS_DISPLAY_TYPE_VIDI:
296                 type = DRM_MODE_CONNECTOR_VIRTUAL;
297                 connector->polled = DRM_CONNECTOR_POLL_HPD;
298                 break;
299         default:
300                 type = DRM_MODE_CONNECTOR_Unknown;
301                 break;
302         }
303
304         drm_connector_init(dev, connector, &exynos_connector_funcs, type);
305         drm_connector_helper_add(connector, &exynos_connector_helper_funcs);
306
307         err = drm_sysfs_connector_add(connector);
308         if (err)
309                 goto err_connector;
310
311         exynos_connector->encoder_id = encoder->base.id;
312         exynos_connector->manager = manager;
313         exynos_connector->dpms = DRM_MODE_DPMS_OFF;
314         connector->dpms = DRM_MODE_DPMS_OFF;
315         connector->encoder = encoder;
316
317         err = drm_mode_connector_attach_encoder(connector, encoder);
318         if (err) {
319                 DRM_ERROR("failed to attach a connector to a encoder\n");
320                 goto err_sysfs;
321         }
322
323         DRM_DEBUG_KMS("connector has been created\n");
324
325         return connector;
326
327 err_sysfs:
328         drm_sysfs_connector_remove(connector);
329 err_connector:
330         drm_connector_cleanup(connector);
331         kfree(exynos_connector);
332         return NULL;
333 }