1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
4 * Author: Rob Clark <rob@ti.com>
7 #include <drm/drm_atomic_helper.h>
8 #include <drm/drm_crtc.h>
9 #include <drm/drm_panel.h>
10 #include <drm/drm_probe_helper.h>
18 #define to_omap_connector(x) container_of(x, struct omap_connector, base)
20 struct omap_connector
{
21 struct drm_connector base
;
22 struct omap_dss_device
*output
;
23 struct omap_dss_device
*hpd
;
27 static void omap_connector_hpd_notify(struct drm_connector
*connector
,
28 enum drm_connector_status status
)
30 struct omap_connector
*omap_connector
= to_omap_connector(connector
);
31 struct omap_dss_device
*dssdev
;
33 if (status
!= connector_status_disconnected
)
37 * Notify all devics in the pipeline of disconnection. This is required
38 * to let the HDMI encoders reset their internal state related to
39 * connection status, such as the CEC address.
41 for (dssdev
= omap_connector
->output
; dssdev
; dssdev
= dssdev
->next
) {
42 if (dssdev
->ops
&& dssdev
->ops
->hdmi
.lost_hotplug
)
43 dssdev
->ops
->hdmi
.lost_hotplug(dssdev
);
47 static void omap_connector_hpd_cb(void *cb_data
,
48 enum drm_connector_status status
)
50 struct omap_connector
*omap_connector
= cb_data
;
51 struct drm_connector
*connector
= &omap_connector
->base
;
52 struct drm_device
*dev
= connector
->dev
;
53 enum drm_connector_status old_status
;
55 mutex_lock(&dev
->mode_config
.mutex
);
56 old_status
= connector
->status
;
57 connector
->status
= status
;
58 mutex_unlock(&dev
->mode_config
.mutex
);
60 if (old_status
== status
)
63 omap_connector_hpd_notify(connector
, status
);
65 drm_kms_helper_hotplug_event(dev
);
68 void omap_connector_enable_hpd(struct drm_connector
*connector
)
70 struct omap_connector
*omap_connector
= to_omap_connector(connector
);
71 struct omap_dss_device
*hpd
= omap_connector
->hpd
;
74 hpd
->ops
->register_hpd_cb(hpd
, omap_connector_hpd_cb
,
78 void omap_connector_disable_hpd(struct drm_connector
*connector
)
80 struct omap_connector
*omap_connector
= to_omap_connector(connector
);
81 struct omap_dss_device
*hpd
= omap_connector
->hpd
;
84 hpd
->ops
->unregister_hpd_cb(hpd
);
87 bool omap_connector_get_hdmi_mode(struct drm_connector
*connector
)
89 struct omap_connector
*omap_connector
= to_omap_connector(connector
);
91 return omap_connector
->hdmi_mode
;
94 static struct omap_dss_device
*
95 omap_connector_find_device(struct drm_connector
*connector
,
96 enum omap_dss_device_ops_flag op
)
98 struct omap_connector
*omap_connector
= to_omap_connector(connector
);
99 struct omap_dss_device
*dssdev
= NULL
;
100 struct omap_dss_device
*d
;
102 for (d
= omap_connector
->output
; d
; d
= d
->next
) {
103 if (d
->ops_flags
& op
)
110 static enum drm_connector_status
omap_connector_detect(
111 struct drm_connector
*connector
, bool force
)
113 struct omap_dss_device
*dssdev
;
114 enum drm_connector_status status
;
116 dssdev
= omap_connector_find_device(connector
,
117 OMAP_DSS_DEVICE_OP_DETECT
);
120 status
= dssdev
->ops
->detect(dssdev
)
121 ? connector_status_connected
122 : connector_status_disconnected
;
124 omap_connector_hpd_notify(connector
, status
);
126 switch (connector
->connector_type
) {
127 case DRM_MODE_CONNECTOR_DPI
:
128 case DRM_MODE_CONNECTOR_LVDS
:
129 case DRM_MODE_CONNECTOR_DSI
:
130 status
= connector_status_connected
;
133 status
= connector_status_unknown
;
138 VERB("%s: %d (force=%d)", connector
->name
, status
, force
);
143 static void omap_connector_destroy(struct drm_connector
*connector
)
145 struct omap_connector
*omap_connector
= to_omap_connector(connector
);
147 DBG("%s", connector
->name
);
149 if (omap_connector
->hpd
) {
150 struct omap_dss_device
*hpd
= omap_connector
->hpd
;
152 hpd
->ops
->unregister_hpd_cb(hpd
);
153 omapdss_device_put(hpd
);
154 omap_connector
->hpd
= NULL
;
157 drm_connector_unregister(connector
);
158 drm_connector_cleanup(connector
);
160 omapdss_device_put(omap_connector
->output
);
162 kfree(omap_connector
);
167 static int omap_connector_get_modes_edid(struct drm_connector
*connector
,
168 struct omap_dss_device
*dssdev
)
170 struct omap_connector
*omap_connector
= to_omap_connector(connector
);
171 enum drm_connector_status status
;
175 status
= omap_connector_detect(connector
, false);
176 if (status
!= connector_status_connected
)
179 edid
= kzalloc(MAX_EDID
, GFP_KERNEL
);
183 if (dssdev
->ops
->read_edid(dssdev
, edid
, MAX_EDID
) <= 0 ||
184 !drm_edid_is_valid(edid
)) {
189 drm_connector_update_edid_property(connector
, edid
);
190 n
= drm_add_edid_modes(connector
, edid
);
192 omap_connector
->hdmi_mode
= drm_detect_hdmi_monitor(edid
);
198 drm_connector_update_edid_property(connector
, NULL
);
202 static int omap_connector_get_modes(struct drm_connector
*connector
)
204 struct omap_connector
*omap_connector
= to_omap_connector(connector
);
205 struct omap_dss_device
*dssdev
;
207 DBG("%s", connector
->name
);
210 * If display exposes EDID, then we parse that in the normal way to
211 * build table of supported modes.
213 dssdev
= omap_connector_find_device(connector
,
214 OMAP_DSS_DEVICE_OP_EDID
);
216 return omap_connector_get_modes_edid(connector
, dssdev
);
219 * Otherwise if the display pipeline reports modes (e.g. with a fixed
220 * resolution panel or an analog TV output), query it.
222 dssdev
= omap_connector_find_device(connector
,
223 OMAP_DSS_DEVICE_OP_MODES
);
225 return dssdev
->ops
->get_modes(dssdev
, connector
);
228 * Otherwise if the display pipeline uses a drm_panel, we delegate the
229 * operation to the panel API.
231 if (omap_connector
->output
->panel
)
232 return drm_panel_get_modes(omap_connector
->output
->panel
,
236 * We can't retrieve modes, which can happen for instance for a DVI or
237 * VGA output with the DDC bus unconnected. The KMS core will add the
243 enum drm_mode_status
omap_connector_mode_fixup(struct omap_dss_device
*dssdev
,
244 const struct drm_display_mode
*mode
,
245 struct drm_display_mode
*adjusted_mode
)
249 drm_mode_copy(adjusted_mode
, mode
);
251 for (; dssdev
; dssdev
= dssdev
->next
) {
252 if (!dssdev
->ops
->check_timings
)
255 ret
= dssdev
->ops
->check_timings(dssdev
, adjusted_mode
);
263 static enum drm_mode_status
omap_connector_mode_valid(struct drm_connector
*connector
,
264 struct drm_display_mode
*mode
)
266 struct omap_connector
*omap_connector
= to_omap_connector(connector
);
267 struct drm_display_mode new_mode
= { { 0 } };
268 enum drm_mode_status status
;
270 status
= omap_connector_mode_fixup(omap_connector
->output
, mode
,
272 if (status
!= MODE_OK
)
275 /* Check if vrefresh is still valid. */
276 if (drm_mode_vrefresh(mode
) != drm_mode_vrefresh(&new_mode
))
277 status
= MODE_NOCLOCK
;
280 DBG("connector: mode %s: " DRM_MODE_FMT
,
281 (status
== MODE_OK
) ? "valid" : "invalid",
287 static const struct drm_connector_funcs omap_connector_funcs
= {
288 .reset
= drm_atomic_helper_connector_reset
,
289 .detect
= omap_connector_detect
,
290 .fill_modes
= drm_helper_probe_single_connector_modes
,
291 .destroy
= omap_connector_destroy
,
292 .atomic_duplicate_state
= drm_atomic_helper_connector_duplicate_state
,
293 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
296 static const struct drm_connector_helper_funcs omap_connector_helper_funcs
= {
297 .get_modes
= omap_connector_get_modes
,
298 .mode_valid
= omap_connector_mode_valid
,
301 static int omap_connector_get_type(struct omap_dss_device
*output
)
303 struct omap_dss_device
*display
;
304 enum omap_display_type type
;
306 display
= omapdss_display_get(output
);
307 type
= display
->type
;
308 omapdss_device_put(display
);
311 case OMAP_DISPLAY_TYPE_HDMI
:
312 return DRM_MODE_CONNECTOR_HDMIA
;
313 case OMAP_DISPLAY_TYPE_DVI
:
314 return DRM_MODE_CONNECTOR_DVID
;
315 case OMAP_DISPLAY_TYPE_DSI
:
316 return DRM_MODE_CONNECTOR_DSI
;
317 case OMAP_DISPLAY_TYPE_DPI
:
318 case OMAP_DISPLAY_TYPE_DBI
:
319 return DRM_MODE_CONNECTOR_DPI
;
320 case OMAP_DISPLAY_TYPE_VENC
:
321 /* TODO: This could also be composite */
322 return DRM_MODE_CONNECTOR_SVIDEO
;
323 case OMAP_DISPLAY_TYPE_SDI
:
324 return DRM_MODE_CONNECTOR_LVDS
;
326 return DRM_MODE_CONNECTOR_Unknown
;
330 /* initialize connector */
331 struct drm_connector
*omap_connector_init(struct drm_device
*dev
,
332 struct omap_dss_device
*output
,
333 struct drm_encoder
*encoder
)
335 struct drm_connector
*connector
= NULL
;
336 struct omap_connector
*omap_connector
;
337 struct omap_dss_device
*dssdev
;
339 DBG("%s", output
->name
);
341 omap_connector
= kzalloc(sizeof(*omap_connector
), GFP_KERNEL
);
345 omap_connector
->output
= omapdss_device_get(output
);
347 connector
= &omap_connector
->base
;
348 connector
->interlace_allowed
= 1;
349 connector
->doublescan_allowed
= 0;
351 drm_connector_init(dev
, connector
, &omap_connector_funcs
,
352 omap_connector_get_type(output
));
353 drm_connector_helper_add(connector
, &omap_connector_helper_funcs
);
356 * Initialize connector status handling. First try to find a device that
357 * supports hot-plug reporting. If it fails, fall back to a device that
358 * support polling. If that fails too, we don't support hot-plug
361 dssdev
= omap_connector_find_device(connector
, OMAP_DSS_DEVICE_OP_HPD
);
363 omap_connector
->hpd
= omapdss_device_get(dssdev
);
364 connector
->polled
= DRM_CONNECTOR_POLL_HPD
;
366 dssdev
= omap_connector_find_device(connector
,
367 OMAP_DSS_DEVICE_OP_DETECT
);
369 connector
->polled
= DRM_CONNECTOR_POLL_CONNECT
|
370 DRM_CONNECTOR_POLL_DISCONNECT
;
377 omap_connector_destroy(connector
);