2 * drivers/gpu/drm/omapdrm/omap_connector.c
4 * Copyright (C) 2011 Texas Instruments
5 * Author: Rob Clark <rob@ti.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "drm_crtc_helper.h"
29 #define to_omap_connector(x) container_of(x, struct omap_connector, base)
31 struct omap_connector
{
32 struct drm_connector base
;
33 struct omap_dss_device
*dssdev
;
34 struct drm_encoder
*encoder
;
38 bool omap_connector_get_hdmi_mode(struct drm_connector
*connector
)
40 struct omap_connector
*omap_connector
= to_omap_connector(connector
);
42 return omap_connector
->hdmi_mode
;
45 void copy_timings_omap_to_drm(struct drm_display_mode
*mode
,
46 struct omap_video_timings
*timings
)
48 mode
->clock
= timings
->pixelclock
/ 1000;
50 mode
->hdisplay
= timings
->x_res
;
51 mode
->hsync_start
= mode
->hdisplay
+ timings
->hfp
;
52 mode
->hsync_end
= mode
->hsync_start
+ timings
->hsw
;
53 mode
->htotal
= mode
->hsync_end
+ timings
->hbp
;
55 mode
->vdisplay
= timings
->y_res
;
56 mode
->vsync_start
= mode
->vdisplay
+ timings
->vfp
;
57 mode
->vsync_end
= mode
->vsync_start
+ timings
->vsw
;
58 mode
->vtotal
= mode
->vsync_end
+ timings
->vbp
;
62 if (timings
->interlace
)
63 mode
->flags
|= DRM_MODE_FLAG_INTERLACE
;
65 if (timings
->hsync_level
== OMAPDSS_SIG_ACTIVE_HIGH
)
66 mode
->flags
|= DRM_MODE_FLAG_PHSYNC
;
68 mode
->flags
|= DRM_MODE_FLAG_NHSYNC
;
70 if (timings
->vsync_level
== OMAPDSS_SIG_ACTIVE_HIGH
)
71 mode
->flags
|= DRM_MODE_FLAG_PVSYNC
;
73 mode
->flags
|= DRM_MODE_FLAG_NVSYNC
;
76 void copy_timings_drm_to_omap(struct omap_video_timings
*timings
,
77 struct drm_display_mode
*mode
)
79 timings
->pixelclock
= mode
->clock
* 1000;
81 timings
->x_res
= mode
->hdisplay
;
82 timings
->hfp
= mode
->hsync_start
- mode
->hdisplay
;
83 timings
->hsw
= mode
->hsync_end
- mode
->hsync_start
;
84 timings
->hbp
= mode
->htotal
- mode
->hsync_end
;
86 timings
->y_res
= mode
->vdisplay
;
87 timings
->vfp
= mode
->vsync_start
- mode
->vdisplay
;
88 timings
->vsw
= mode
->vsync_end
- mode
->vsync_start
;
89 timings
->vbp
= mode
->vtotal
- mode
->vsync_end
;
91 timings
->interlace
= !!(mode
->flags
& DRM_MODE_FLAG_INTERLACE
);
93 if (mode
->flags
& DRM_MODE_FLAG_PHSYNC
)
94 timings
->hsync_level
= OMAPDSS_SIG_ACTIVE_HIGH
;
96 timings
->hsync_level
= OMAPDSS_SIG_ACTIVE_LOW
;
98 if (mode
->flags
& DRM_MODE_FLAG_PVSYNC
)
99 timings
->vsync_level
= OMAPDSS_SIG_ACTIVE_HIGH
;
101 timings
->vsync_level
= OMAPDSS_SIG_ACTIVE_LOW
;
103 timings
->data_pclk_edge
= OMAPDSS_DRIVE_SIG_RISING_EDGE
;
104 timings
->de_level
= OMAPDSS_SIG_ACTIVE_HIGH
;
105 timings
->sync_pclk_edge
= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES
;
108 static enum drm_connector_status
omap_connector_detect(
109 struct drm_connector
*connector
, bool force
)
111 struct omap_connector
*omap_connector
= to_omap_connector(connector
);
112 struct omap_dss_device
*dssdev
= omap_connector
->dssdev
;
113 struct omap_dss_driver
*dssdrv
= dssdev
->driver
;
114 enum drm_connector_status ret
;
116 if (dssdrv
->detect
) {
117 if (dssdrv
->detect(dssdev
))
118 ret
= connector_status_connected
;
120 ret
= connector_status_disconnected
;
121 } else if (dssdev
->type
== OMAP_DISPLAY_TYPE_DPI
||
122 dssdev
->type
== OMAP_DISPLAY_TYPE_DBI
||
123 dssdev
->type
== OMAP_DISPLAY_TYPE_SDI
||
124 dssdev
->type
== OMAP_DISPLAY_TYPE_DSI
) {
125 ret
= connector_status_connected
;
127 ret
= connector_status_unknown
;
130 VERB("%s: %d (force=%d)", omap_connector
->dssdev
->name
, ret
, force
);
135 static void omap_connector_destroy(struct drm_connector
*connector
)
137 struct omap_connector
*omap_connector
= to_omap_connector(connector
);
138 struct omap_dss_device
*dssdev
= omap_connector
->dssdev
;
140 DBG("%s", omap_connector
->dssdev
->name
);
141 drm_connector_unregister(connector
);
142 drm_connector_cleanup(connector
);
143 kfree(omap_connector
);
145 omap_dss_put_device(dssdev
);
150 static int omap_connector_get_modes(struct drm_connector
*connector
)
152 struct omap_connector
*omap_connector
= to_omap_connector(connector
);
153 struct omap_dss_device
*dssdev
= omap_connector
->dssdev
;
154 struct omap_dss_driver
*dssdrv
= dssdev
->driver
;
155 struct drm_device
*dev
= connector
->dev
;
158 DBG("%s", omap_connector
->dssdev
->name
);
160 /* if display exposes EDID, then we parse that in the normal way to
161 * build table of supported modes.. otherwise (ie. fixed resolution
162 * LCD panels) we just return a single mode corresponding to the
163 * currently configured timings:
165 if (dssdrv
->read_edid
) {
166 void *edid
= kzalloc(MAX_EDID
, GFP_KERNEL
);
168 if ((dssdrv
->read_edid(dssdev
, edid
, MAX_EDID
) > 0) &&
169 drm_edid_is_valid(edid
)) {
170 drm_mode_connector_update_edid_property(
172 n
= drm_add_edid_modes(connector
, edid
);
174 omap_connector
->hdmi_mode
=
175 drm_detect_hdmi_monitor(edid
);
177 drm_mode_connector_update_edid_property(
183 struct drm_display_mode
*mode
= drm_mode_create(dev
);
184 struct omap_video_timings timings
= {0};
186 dssdrv
->get_timings(dssdev
, &timings
);
188 copy_timings_omap_to_drm(mode
, &timings
);
190 mode
->type
= DRM_MODE_TYPE_DRIVER
| DRM_MODE_TYPE_PREFERRED
;
191 drm_mode_set_name(mode
);
192 drm_mode_probed_add(connector
, mode
);
200 static int omap_connector_mode_valid(struct drm_connector
*connector
,
201 struct drm_display_mode
*mode
)
203 struct omap_connector
*omap_connector
= to_omap_connector(connector
);
204 struct omap_dss_device
*dssdev
= omap_connector
->dssdev
;
205 struct omap_dss_driver
*dssdrv
= dssdev
->driver
;
206 struct omap_video_timings timings
= {0};
207 struct drm_device
*dev
= connector
->dev
;
208 struct drm_display_mode
*new_mode
;
209 int r
, ret
= MODE_BAD
;
211 copy_timings_drm_to_omap(&timings
, mode
);
212 mode
->vrefresh
= drm_mode_vrefresh(mode
);
215 * if the panel driver doesn't have a check_timings, it's most likely
216 * a fixed resolution panel, check if the timings match with the
219 if (dssdrv
->check_timings
) {
220 r
= dssdrv
->check_timings(dssdev
, &timings
);
222 struct omap_video_timings t
= {0};
224 dssdrv
->get_timings(dssdev
, &t
);
226 if (memcmp(&timings
, &t
, sizeof(struct omap_video_timings
)))
233 /* check if vrefresh is still valid */
234 new_mode
= drm_mode_duplicate(dev
, mode
);
235 new_mode
->clock
= timings
.pixelclock
/ 1000;
236 new_mode
->vrefresh
= 0;
237 if (mode
->vrefresh
== drm_mode_vrefresh(new_mode
))
239 drm_mode_destroy(dev
, new_mode
);
242 DBG("connector: mode %s: "
243 "%d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
244 (ret
== MODE_OK
) ? "valid" : "invalid",
245 mode
->base
.id
, mode
->name
, mode
->vrefresh
, mode
->clock
,
246 mode
->hdisplay
, mode
->hsync_start
,
247 mode
->hsync_end
, mode
->htotal
,
248 mode
->vdisplay
, mode
->vsync_start
,
249 mode
->vsync_end
, mode
->vtotal
, mode
->type
, mode
->flags
);
254 struct drm_encoder
*omap_connector_attached_encoder(
255 struct drm_connector
*connector
)
257 struct omap_connector
*omap_connector
= to_omap_connector(connector
);
258 return omap_connector
->encoder
;
261 static const struct drm_connector_funcs omap_connector_funcs
= {
262 .dpms
= drm_helper_connector_dpms
,
263 .detect
= omap_connector_detect
,
264 .fill_modes
= drm_helper_probe_single_connector_modes
,
265 .destroy
= omap_connector_destroy
,
268 static const struct drm_connector_helper_funcs omap_connector_helper_funcs
= {
269 .get_modes
= omap_connector_get_modes
,
270 .mode_valid
= omap_connector_mode_valid
,
271 .best_encoder
= omap_connector_attached_encoder
,
274 /* flush an area of the framebuffer (in case of manual update display that
275 * is not automatically flushed)
277 void omap_connector_flush(struct drm_connector
*connector
,
278 int x
, int y
, int w
, int h
)
280 struct omap_connector
*omap_connector
= to_omap_connector(connector
);
282 /* TODO: enable when supported in dss */
283 VERB("%s: %d,%d, %dx%d", omap_connector
->dssdev
->name
, x
, y
, w
, h
);
286 /* initialize connector */
287 struct drm_connector
*omap_connector_init(struct drm_device
*dev
,
288 int connector_type
, struct omap_dss_device
*dssdev
,
289 struct drm_encoder
*encoder
)
291 struct drm_connector
*connector
= NULL
;
292 struct omap_connector
*omap_connector
;
294 DBG("%s", dssdev
->name
);
296 omap_dss_get_device(dssdev
);
298 omap_connector
= kzalloc(sizeof(struct omap_connector
), GFP_KERNEL
);
302 omap_connector
->dssdev
= dssdev
;
303 omap_connector
->encoder
= encoder
;
305 connector
= &omap_connector
->base
;
307 drm_connector_init(dev
, connector
, &omap_connector_funcs
,
309 drm_connector_helper_add(connector
, &omap_connector_helper_funcs
);
311 #if 0 /* enable when dss2 supports hotplug */
312 if (dssdev
->caps
& OMAP_DSS_DISPLAY_CAP_HPD
)
313 connector
->polled
= 0;
316 connector
->polled
= DRM_CONNECTOR_POLL_CONNECT
|
317 DRM_CONNECTOR_POLL_DISCONNECT
;
319 connector
->interlace_allowed
= 1;
320 connector
->doublescan_allowed
= 0;
322 drm_connector_register(connector
);
328 omap_connector_destroy(connector
);