1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Copyright (C) 2019 Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
4 | */ |
5 | |
6 | #include <linux/kernel.h> |
7 | #include <linux/module.h> |
8 | #include <linux/of.h> |
9 | #include <linux/property.h> |
10 | #include <linux/slab.h> |
11 | |
12 | #include <drm/drm_atomic_state_helper.h> |
13 | #include <drm/drm_bridge.h> |
14 | #include <drm/drm_bridge_connector.h> |
15 | #include <drm/drm_connector.h> |
16 | #include <drm/drm_device.h> |
17 | #include <drm/drm_edid.h> |
18 | #include <drm/drm_modeset_helper_vtables.h> |
19 | #include <drm/drm_probe_helper.h> |
20 | |
21 | /** |
22 | * DOC: overview |
23 | * |
24 | * The DRM bridge connector helper object provides a DRM connector |
25 | * implementation that wraps a chain of &struct drm_bridge. The connector |
26 | * operations are fully implemented based on the operations of the bridges in |
27 | * the chain, and don't require any intervention from the display controller |
28 | * driver at runtime. |
29 | * |
30 | * To use the helper, display controller drivers create a bridge connector with |
31 | * a call to drm_bridge_connector_init(). This associates the newly created |
32 | * connector with the chain of bridges passed to the function and registers it |
33 | * with the DRM device. At that point the connector becomes fully usable, no |
34 | * further operation is needed. |
35 | * |
36 | * The DRM bridge connector operations are implemented based on the operations |
37 | * provided by the bridges in the chain. Each connector operation is delegated |
38 | * to the bridge closest to the connector (at the end of the chain) that |
39 | * provides the relevant functionality. |
40 | * |
41 | * To make use of this helper, all bridges in the chain shall report bridge |
42 | * operation flags (&drm_bridge->ops) and bridge output type |
43 | * (&drm_bridge->type), as well as the DRM_BRIDGE_ATTACH_NO_CONNECTOR attach |
44 | * flag (none of the bridges shall create a DRM connector directly). |
45 | */ |
46 | |
47 | /** |
48 | * struct drm_bridge_connector - A connector backed by a chain of bridges |
49 | */ |
50 | struct drm_bridge_connector { |
51 | /** |
52 | * @base: The base DRM connector |
53 | */ |
54 | struct drm_connector base; |
55 | /** |
56 | * @encoder: |
57 | * |
58 | * The encoder at the start of the bridges chain. |
59 | */ |
60 | struct drm_encoder *encoder; |
61 | /** |
62 | * @bridge_edid: |
63 | * |
64 | * The last bridge in the chain (closest to the connector) that provides |
65 | * EDID read support, if any (see &DRM_BRIDGE_OP_EDID). |
66 | */ |
67 | struct drm_bridge *bridge_edid; |
68 | /** |
69 | * @bridge_hpd: |
70 | * |
71 | * The last bridge in the chain (closest to the connector) that provides |
72 | * hot-plug detection notification, if any (see &DRM_BRIDGE_OP_HPD). |
73 | */ |
74 | struct drm_bridge *bridge_hpd; |
75 | /** |
76 | * @bridge_detect: |
77 | * |
78 | * The last bridge in the chain (closest to the connector) that provides |
79 | * connector detection, if any (see &DRM_BRIDGE_OP_DETECT). |
80 | */ |
81 | struct drm_bridge *bridge_detect; |
82 | /** |
83 | * @bridge_modes: |
84 | * |
85 | * The last bridge in the chain (closest to the connector) that provides |
86 | * connector modes detection, if any (see &DRM_BRIDGE_OP_MODES). |
87 | */ |
88 | struct drm_bridge *bridge_modes; |
89 | }; |
90 | |
91 | #define to_drm_bridge_connector(x) \ |
92 | container_of(x, struct drm_bridge_connector, base) |
93 | |
94 | /* ----------------------------------------------------------------------------- |
95 | * Bridge Connector Hot-Plug Handling |
96 | */ |
97 | |
98 | static void drm_bridge_connector_hpd_notify(struct drm_connector *connector, |
99 | enum drm_connector_status status) |
100 | { |
101 | struct drm_bridge_connector *bridge_connector = |
102 | to_drm_bridge_connector(connector); |
103 | struct drm_bridge *bridge; |
104 | |
105 | /* Notify all bridges in the pipeline of hotplug events. */ |
106 | drm_for_each_bridge_in_chain(bridge_connector->encoder, bridge) { |
107 | if (bridge->funcs->hpd_notify) |
108 | bridge->funcs->hpd_notify(bridge, status); |
109 | } |
110 | } |
111 | |
112 | static void drm_bridge_connector_handle_hpd(struct drm_bridge_connector *drm_bridge_connector, |
113 | enum drm_connector_status status) |
114 | { |
115 | struct drm_connector *connector = &drm_bridge_connector->base; |
116 | struct drm_device *dev = connector->dev; |
117 | |
118 | mutex_lock(&dev->mode_config.mutex); |
119 | connector->status = status; |
120 | mutex_unlock(lock: &dev->mode_config.mutex); |
121 | |
122 | drm_bridge_connector_hpd_notify(connector, status); |
123 | |
124 | drm_kms_helper_connector_hotplug_event(connector); |
125 | } |
126 | |
127 | static void drm_bridge_connector_hpd_cb(void *cb_data, |
128 | enum drm_connector_status status) |
129 | { |
130 | drm_bridge_connector_handle_hpd(drm_bridge_connector: cb_data, status); |
131 | } |
132 | |
133 | static void drm_bridge_connector_oob_hotplug_event(struct drm_connector *connector, |
134 | enum drm_connector_status status) |
135 | { |
136 | struct drm_bridge_connector *bridge_connector = |
137 | to_drm_bridge_connector(connector); |
138 | |
139 | drm_bridge_connector_handle_hpd(drm_bridge_connector: bridge_connector, status); |
140 | } |
141 | |
142 | static void drm_bridge_connector_enable_hpd(struct drm_connector *connector) |
143 | { |
144 | struct drm_bridge_connector *bridge_connector = |
145 | to_drm_bridge_connector(connector); |
146 | struct drm_bridge *hpd = bridge_connector->bridge_hpd; |
147 | |
148 | if (hpd) |
149 | drm_bridge_hpd_enable(bridge: hpd, cb: drm_bridge_connector_hpd_cb, |
150 | data: bridge_connector); |
151 | } |
152 | |
153 | static void drm_bridge_connector_disable_hpd(struct drm_connector *connector) |
154 | { |
155 | struct drm_bridge_connector *bridge_connector = |
156 | to_drm_bridge_connector(connector); |
157 | struct drm_bridge *hpd = bridge_connector->bridge_hpd; |
158 | |
159 | if (hpd) |
160 | drm_bridge_hpd_disable(bridge: hpd); |
161 | } |
162 | |
163 | /* ----------------------------------------------------------------------------- |
164 | * Bridge Connector Functions |
165 | */ |
166 | |
167 | static enum drm_connector_status |
168 | drm_bridge_connector_detect(struct drm_connector *connector, bool force) |
169 | { |
170 | struct drm_bridge_connector *bridge_connector = |
171 | to_drm_bridge_connector(connector); |
172 | struct drm_bridge *detect = bridge_connector->bridge_detect; |
173 | enum drm_connector_status status; |
174 | |
175 | if (detect) { |
176 | status = detect->funcs->detect(detect); |
177 | |
178 | drm_bridge_connector_hpd_notify(connector, status); |
179 | } else { |
180 | switch (connector->connector_type) { |
181 | case DRM_MODE_CONNECTOR_DPI: |
182 | case DRM_MODE_CONNECTOR_LVDS: |
183 | case DRM_MODE_CONNECTOR_DSI: |
184 | case DRM_MODE_CONNECTOR_eDP: |
185 | status = connector_status_connected; |
186 | break; |
187 | default: |
188 | status = connector_status_unknown; |
189 | break; |
190 | } |
191 | } |
192 | |
193 | return status; |
194 | } |
195 | |
196 | static void drm_bridge_connector_destroy(struct drm_connector *connector) |
197 | { |
198 | struct drm_bridge_connector *bridge_connector = |
199 | to_drm_bridge_connector(connector); |
200 | |
201 | if (bridge_connector->bridge_hpd) { |
202 | struct drm_bridge *hpd = bridge_connector->bridge_hpd; |
203 | |
204 | drm_bridge_hpd_disable(bridge: hpd); |
205 | } |
206 | |
207 | drm_connector_unregister(connector); |
208 | drm_connector_cleanup(connector); |
209 | |
210 | fwnode_handle_put(fwnode: connector->fwnode); |
211 | |
212 | kfree(objp: bridge_connector); |
213 | } |
214 | |
215 | static void drm_bridge_connector_debugfs_init(struct drm_connector *connector, |
216 | struct dentry *root) |
217 | { |
218 | struct drm_bridge_connector *bridge_connector = |
219 | to_drm_bridge_connector(connector); |
220 | struct drm_encoder *encoder = bridge_connector->encoder; |
221 | struct drm_bridge *bridge; |
222 | |
223 | list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) { |
224 | if (bridge->funcs->debugfs_init) |
225 | bridge->funcs->debugfs_init(bridge, root); |
226 | } |
227 | } |
228 | |
229 | static const struct drm_connector_funcs drm_bridge_connector_funcs = { |
230 | .reset = drm_atomic_helper_connector_reset, |
231 | .detect = drm_bridge_connector_detect, |
232 | .fill_modes = drm_helper_probe_single_connector_modes, |
233 | .destroy = drm_bridge_connector_destroy, |
234 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
235 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
236 | .debugfs_init = drm_bridge_connector_debugfs_init, |
237 | .oob_hotplug_event = drm_bridge_connector_oob_hotplug_event, |
238 | }; |
239 | |
240 | /* ----------------------------------------------------------------------------- |
241 | * Bridge Connector Helper Functions |
242 | */ |
243 | |
244 | static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector, |
245 | struct drm_bridge *bridge) |
246 | { |
247 | enum drm_connector_status status; |
248 | struct edid *edid; |
249 | int n; |
250 | |
251 | status = drm_bridge_connector_detect(connector, force: false); |
252 | if (status != connector_status_connected) |
253 | goto no_edid; |
254 | |
255 | edid = drm_bridge_get_edid(bridge, connector); |
256 | if (!drm_edid_is_valid(edid)) { |
257 | kfree(objp: edid); |
258 | goto no_edid; |
259 | } |
260 | |
261 | drm_connector_update_edid_property(connector, edid); |
262 | n = drm_add_edid_modes(connector, edid); |
263 | |
264 | kfree(objp: edid); |
265 | return n; |
266 | |
267 | no_edid: |
268 | drm_connector_update_edid_property(connector, NULL); |
269 | return 0; |
270 | } |
271 | |
272 | static int drm_bridge_connector_get_modes(struct drm_connector *connector) |
273 | { |
274 | struct drm_bridge_connector *bridge_connector = |
275 | to_drm_bridge_connector(connector); |
276 | struct drm_bridge *bridge; |
277 | |
278 | /* |
279 | * If display exposes EDID, then we parse that in the normal way to |
280 | * build table of supported modes. |
281 | */ |
282 | bridge = bridge_connector->bridge_edid; |
283 | if (bridge) |
284 | return drm_bridge_connector_get_modes_edid(connector, bridge); |
285 | |
286 | /* |
287 | * Otherwise if the display pipeline reports modes (e.g. with a fixed |
288 | * resolution panel or an analog TV output), query it. |
289 | */ |
290 | bridge = bridge_connector->bridge_modes; |
291 | if (bridge) |
292 | return bridge->funcs->get_modes(bridge, connector); |
293 | |
294 | /* |
295 | * We can't retrieve modes, which can happen for instance for a DVI or |
296 | * VGA output with the DDC bus unconnected. The KMS core will add the |
297 | * default modes. |
298 | */ |
299 | return 0; |
300 | } |
301 | |
302 | static const struct drm_connector_helper_funcs drm_bridge_connector_helper_funcs = { |
303 | .get_modes = drm_bridge_connector_get_modes, |
304 | /* No need for .mode_valid(), the bridges are checked by the core. */ |
305 | .enable_hpd = drm_bridge_connector_enable_hpd, |
306 | .disable_hpd = drm_bridge_connector_disable_hpd, |
307 | }; |
308 | |
309 | /* ----------------------------------------------------------------------------- |
310 | * Bridge Connector Initialisation |
311 | */ |
312 | |
313 | /** |
314 | * drm_bridge_connector_init - Initialise a connector for a chain of bridges |
315 | * @drm: the DRM device |
316 | * @encoder: the encoder where the bridge chain starts |
317 | * |
318 | * Allocate, initialise and register a &drm_bridge_connector with the @drm |
319 | * device. The connector is associated with a chain of bridges that starts at |
320 | * the @encoder. All bridges in the chain shall report bridge operation flags |
321 | * (&drm_bridge->ops) and bridge output type (&drm_bridge->type), and none of |
322 | * them may create a DRM connector directly. |
323 | * |
324 | * Returns a pointer to the new connector on success, or a negative error |
325 | * pointer otherwise. |
326 | */ |
327 | struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, |
328 | struct drm_encoder *encoder) |
329 | { |
330 | struct drm_bridge_connector *bridge_connector; |
331 | struct drm_connector *connector; |
332 | struct i2c_adapter *ddc = NULL; |
333 | struct drm_bridge *bridge, *panel_bridge = NULL; |
334 | int connector_type; |
335 | int ret; |
336 | |
337 | bridge_connector = kzalloc(size: sizeof(*bridge_connector), GFP_KERNEL); |
338 | if (!bridge_connector) |
339 | return ERR_PTR(error: -ENOMEM); |
340 | |
341 | bridge_connector->encoder = encoder; |
342 | |
343 | /* |
344 | * TODO: Handle doublescan_allowed, stereo_allowed and |
345 | * ycbcr_420_allowed. |
346 | */ |
347 | connector = &bridge_connector->base; |
348 | connector->interlace_allowed = true; |
349 | |
350 | /* |
351 | * Initialise connector status handling. First locate the furthest |
352 | * bridges in the pipeline that support HPD and output detection. Then |
353 | * initialise the connector polling mode, using HPD if available and |
354 | * falling back to polling if supported. If neither HPD nor output |
355 | * detection are available, we don't support hotplug detection at all. |
356 | */ |
357 | connector_type = DRM_MODE_CONNECTOR_Unknown; |
358 | drm_for_each_bridge_in_chain(encoder, bridge) { |
359 | if (!bridge->interlace_allowed) |
360 | connector->interlace_allowed = false; |
361 | |
362 | if (bridge->ops & DRM_BRIDGE_OP_EDID) |
363 | bridge_connector->bridge_edid = bridge; |
364 | if (bridge->ops & DRM_BRIDGE_OP_HPD) |
365 | bridge_connector->bridge_hpd = bridge; |
366 | if (bridge->ops & DRM_BRIDGE_OP_DETECT) |
367 | bridge_connector->bridge_detect = bridge; |
368 | if (bridge->ops & DRM_BRIDGE_OP_MODES) |
369 | bridge_connector->bridge_modes = bridge; |
370 | |
371 | if (!drm_bridge_get_next_bridge(bridge)) |
372 | connector_type = bridge->type; |
373 | |
374 | #ifdef CONFIG_OF |
375 | if (!drm_bridge_get_next_bridge(bridge) && |
376 | bridge->of_node) |
377 | connector->fwnode = fwnode_handle_get(of_fwnode_handle(bridge->of_node)); |
378 | #endif |
379 | |
380 | if (bridge->ddc) |
381 | ddc = bridge->ddc; |
382 | |
383 | if (drm_bridge_is_panel(bridge)) |
384 | panel_bridge = bridge; |
385 | } |
386 | |
387 | if (connector_type == DRM_MODE_CONNECTOR_Unknown) { |
388 | kfree(objp: bridge_connector); |
389 | return ERR_PTR(error: -EINVAL); |
390 | } |
391 | |
392 | ret = drm_connector_init_with_ddc(dev: drm, connector, |
393 | funcs: &drm_bridge_connector_funcs, |
394 | connector_type, ddc); |
395 | if (ret) { |
396 | kfree(objp: bridge_connector); |
397 | return ERR_PTR(error: ret); |
398 | } |
399 | |
400 | drm_connector_helper_add(connector, funcs: &drm_bridge_connector_helper_funcs); |
401 | |
402 | if (bridge_connector->bridge_hpd) |
403 | connector->polled = DRM_CONNECTOR_POLL_HPD; |
404 | else if (bridge_connector->bridge_detect) |
405 | connector->polled = DRM_CONNECTOR_POLL_CONNECT |
406 | | DRM_CONNECTOR_POLL_DISCONNECT; |
407 | |
408 | if (panel_bridge) |
409 | drm_panel_bridge_set_orientation(connector, bridge: panel_bridge); |
410 | |
411 | return connector; |
412 | } |
413 | EXPORT_SYMBOL_GPL(drm_bridge_connector_init); |
414 | |