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 | drm_connector_unregister(connector); |
202 | drm_connector_cleanup(connector); |
203 | |
204 | fwnode_handle_put(fwnode: connector->fwnode); |
205 | |
206 | kfree(objp: bridge_connector); |
207 | } |
208 | |
209 | static void drm_bridge_connector_debugfs_init(struct drm_connector *connector, |
210 | struct dentry *root) |
211 | { |
212 | struct drm_bridge_connector *bridge_connector = |
213 | to_drm_bridge_connector(connector); |
214 | struct drm_encoder *encoder = bridge_connector->encoder; |
215 | struct drm_bridge *bridge; |
216 | |
217 | list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) { |
218 | if (bridge->funcs->debugfs_init) |
219 | bridge->funcs->debugfs_init(bridge, root); |
220 | } |
221 | } |
222 | |
223 | static const struct drm_connector_funcs drm_bridge_connector_funcs = { |
224 | .reset = drm_atomic_helper_connector_reset, |
225 | .detect = drm_bridge_connector_detect, |
226 | .fill_modes = drm_helper_probe_single_connector_modes, |
227 | .destroy = drm_bridge_connector_destroy, |
228 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
229 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
230 | .debugfs_init = drm_bridge_connector_debugfs_init, |
231 | .oob_hotplug_event = drm_bridge_connector_oob_hotplug_event, |
232 | }; |
233 | |
234 | /* ----------------------------------------------------------------------------- |
235 | * Bridge Connector Helper Functions |
236 | */ |
237 | |
238 | static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector, |
239 | struct drm_bridge *bridge) |
240 | { |
241 | enum drm_connector_status status; |
242 | const struct drm_edid *drm_edid; |
243 | int n; |
244 | |
245 | status = drm_bridge_connector_detect(connector, force: false); |
246 | if (status != connector_status_connected) |
247 | goto no_edid; |
248 | |
249 | drm_edid = drm_bridge_edid_read(bridge, connector); |
250 | if (!drm_edid_valid(drm_edid)) { |
251 | drm_edid_free(drm_edid); |
252 | goto no_edid; |
253 | } |
254 | |
255 | drm_edid_connector_update(connector, edid: drm_edid); |
256 | n = drm_edid_connector_add_modes(connector); |
257 | |
258 | drm_edid_free(drm_edid); |
259 | return n; |
260 | |
261 | no_edid: |
262 | drm_edid_connector_update(connector, NULL); |
263 | return 0; |
264 | } |
265 | |
266 | static int drm_bridge_connector_get_modes(struct drm_connector *connector) |
267 | { |
268 | struct drm_bridge_connector *bridge_connector = |
269 | to_drm_bridge_connector(connector); |
270 | struct drm_bridge *bridge; |
271 | |
272 | /* |
273 | * If display exposes EDID, then we parse that in the normal way to |
274 | * build table of supported modes. |
275 | */ |
276 | bridge = bridge_connector->bridge_edid; |
277 | if (bridge) |
278 | return drm_bridge_connector_get_modes_edid(connector, bridge); |
279 | |
280 | /* |
281 | * Otherwise if the display pipeline reports modes (e.g. with a fixed |
282 | * resolution panel or an analog TV output), query it. |
283 | */ |
284 | bridge = bridge_connector->bridge_modes; |
285 | if (bridge) |
286 | return bridge->funcs->get_modes(bridge, connector); |
287 | |
288 | /* |
289 | * We can't retrieve modes, which can happen for instance for a DVI or |
290 | * VGA output with the DDC bus unconnected. The KMS core will add the |
291 | * default modes. |
292 | */ |
293 | return 0; |
294 | } |
295 | |
296 | static const struct drm_connector_helper_funcs drm_bridge_connector_helper_funcs = { |
297 | .get_modes = drm_bridge_connector_get_modes, |
298 | /* No need for .mode_valid(), the bridges are checked by the core. */ |
299 | .enable_hpd = drm_bridge_connector_enable_hpd, |
300 | .disable_hpd = drm_bridge_connector_disable_hpd, |
301 | }; |
302 | |
303 | /* ----------------------------------------------------------------------------- |
304 | * Bridge Connector Initialisation |
305 | */ |
306 | |
307 | /** |
308 | * drm_bridge_connector_init - Initialise a connector for a chain of bridges |
309 | * @drm: the DRM device |
310 | * @encoder: the encoder where the bridge chain starts |
311 | * |
312 | * Allocate, initialise and register a &drm_bridge_connector with the @drm |
313 | * device. The connector is associated with a chain of bridges that starts at |
314 | * the @encoder. All bridges in the chain shall report bridge operation flags |
315 | * (&drm_bridge->ops) and bridge output type (&drm_bridge->type), and none of |
316 | * them may create a DRM connector directly. |
317 | * |
318 | * Returns a pointer to the new connector on success, or a negative error |
319 | * pointer otherwise. |
320 | */ |
321 | struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, |
322 | struct drm_encoder *encoder) |
323 | { |
324 | struct drm_bridge_connector *bridge_connector; |
325 | struct drm_connector *connector; |
326 | struct i2c_adapter *ddc = NULL; |
327 | struct drm_bridge *bridge, *panel_bridge = NULL; |
328 | int connector_type; |
329 | int ret; |
330 | |
331 | bridge_connector = kzalloc(size: sizeof(*bridge_connector), GFP_KERNEL); |
332 | if (!bridge_connector) |
333 | return ERR_PTR(error: -ENOMEM); |
334 | |
335 | bridge_connector->encoder = encoder; |
336 | |
337 | /* |
338 | * TODO: Handle doublescan_allowed, stereo_allowed and |
339 | * ycbcr_420_allowed. |
340 | */ |
341 | connector = &bridge_connector->base; |
342 | connector->interlace_allowed = true; |
343 | |
344 | /* |
345 | * Initialise connector status handling. First locate the furthest |
346 | * bridges in the pipeline that support HPD and output detection. Then |
347 | * initialise the connector polling mode, using HPD if available and |
348 | * falling back to polling if supported. If neither HPD nor output |
349 | * detection are available, we don't support hotplug detection at all. |
350 | */ |
351 | connector_type = DRM_MODE_CONNECTOR_Unknown; |
352 | drm_for_each_bridge_in_chain(encoder, bridge) { |
353 | if (!bridge->interlace_allowed) |
354 | connector->interlace_allowed = false; |
355 | |
356 | if (bridge->ops & DRM_BRIDGE_OP_EDID) |
357 | bridge_connector->bridge_edid = bridge; |
358 | if (bridge->ops & DRM_BRIDGE_OP_HPD) |
359 | bridge_connector->bridge_hpd = bridge; |
360 | if (bridge->ops & DRM_BRIDGE_OP_DETECT) |
361 | bridge_connector->bridge_detect = bridge; |
362 | if (bridge->ops & DRM_BRIDGE_OP_MODES) |
363 | bridge_connector->bridge_modes = bridge; |
364 | |
365 | if (!drm_bridge_get_next_bridge(bridge)) |
366 | connector_type = bridge->type; |
367 | |
368 | #ifdef CONFIG_OF |
369 | if (!drm_bridge_get_next_bridge(bridge) && |
370 | bridge->of_node) |
371 | connector->fwnode = fwnode_handle_get(of_fwnode_handle(bridge->of_node)); |
372 | #endif |
373 | |
374 | if (bridge->ddc) |
375 | ddc = bridge->ddc; |
376 | |
377 | if (drm_bridge_is_panel(bridge)) |
378 | panel_bridge = bridge; |
379 | } |
380 | |
381 | if (connector_type == DRM_MODE_CONNECTOR_Unknown) { |
382 | kfree(objp: bridge_connector); |
383 | return ERR_PTR(error: -EINVAL); |
384 | } |
385 | |
386 | ret = drm_connector_init_with_ddc(dev: drm, connector, |
387 | funcs: &drm_bridge_connector_funcs, |
388 | connector_type, ddc); |
389 | if (ret) { |
390 | kfree(objp: bridge_connector); |
391 | return ERR_PTR(error: ret); |
392 | } |
393 | |
394 | drm_connector_helper_add(connector, funcs: &drm_bridge_connector_helper_funcs); |
395 | |
396 | if (bridge_connector->bridge_hpd) |
397 | connector->polled = DRM_CONNECTOR_POLL_HPD; |
398 | else if (bridge_connector->bridge_detect) |
399 | connector->polled = DRM_CONNECTOR_POLL_CONNECT |
400 | | DRM_CONNECTOR_POLL_DISCONNECT; |
401 | |
402 | if (panel_bridge) |
403 | drm_panel_bridge_set_orientation(connector, bridge: panel_bridge); |
404 | |
405 | return connector; |
406 | } |
407 | EXPORT_SYMBOL_GPL(drm_bridge_connector_init); |
408 | |