1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
4 | * Copyright (C) 2017 Broadcom |
5 | */ |
6 | |
7 | #include <drm/drm_atomic_helper.h> |
8 | #include <drm/drm_bridge.h> |
9 | #include <drm/drm_connector.h> |
10 | #include <drm/drm_encoder.h> |
11 | #include <drm/drm_managed.h> |
12 | #include <drm/drm_modeset_helper_vtables.h> |
13 | #include <drm/drm_of.h> |
14 | #include <drm/drm_panel.h> |
15 | #include <drm/drm_print.h> |
16 | #include <drm/drm_probe_helper.h> |
17 | |
18 | struct panel_bridge { |
19 | struct drm_bridge bridge; |
20 | struct drm_connector connector; |
21 | struct drm_panel *panel; |
22 | u32 connector_type; |
23 | }; |
24 | |
25 | static inline struct panel_bridge * |
26 | drm_bridge_to_panel_bridge(struct drm_bridge *bridge) |
27 | { |
28 | return container_of(bridge, struct panel_bridge, bridge); |
29 | } |
30 | |
31 | static inline struct panel_bridge * |
32 | drm_connector_to_panel_bridge(struct drm_connector *connector) |
33 | { |
34 | return container_of(connector, struct panel_bridge, connector); |
35 | } |
36 | |
37 | static int panel_bridge_connector_get_modes(struct drm_connector *connector) |
38 | { |
39 | struct panel_bridge *panel_bridge = |
40 | drm_connector_to_panel_bridge(connector); |
41 | |
42 | return drm_panel_get_modes(panel: panel_bridge->panel, connector); |
43 | } |
44 | |
45 | static const struct drm_connector_helper_funcs |
46 | panel_bridge_connector_helper_funcs = { |
47 | .get_modes = panel_bridge_connector_get_modes, |
48 | }; |
49 | |
50 | static const struct drm_connector_funcs panel_bridge_connector_funcs = { |
51 | .reset = drm_atomic_helper_connector_reset, |
52 | .fill_modes = drm_helper_probe_single_connector_modes, |
53 | .destroy = drm_connector_cleanup, |
54 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
55 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
56 | }; |
57 | |
58 | static int panel_bridge_attach(struct drm_bridge *bridge, |
59 | enum drm_bridge_attach_flags flags) |
60 | { |
61 | struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); |
62 | struct drm_connector *connector = &panel_bridge->connector; |
63 | int ret; |
64 | |
65 | if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) |
66 | return 0; |
67 | |
68 | if (!bridge->encoder) { |
69 | DRM_ERROR("Missing encoder\n" ); |
70 | return -ENODEV; |
71 | } |
72 | |
73 | drm_connector_helper_add(connector, |
74 | funcs: &panel_bridge_connector_helper_funcs); |
75 | |
76 | ret = drm_connector_init(dev: bridge->dev, connector, |
77 | funcs: &panel_bridge_connector_funcs, |
78 | connector_type: panel_bridge->connector_type); |
79 | if (ret) { |
80 | DRM_ERROR("Failed to initialize connector\n" ); |
81 | return ret; |
82 | } |
83 | |
84 | drm_panel_bridge_set_orientation(connector, bridge); |
85 | |
86 | drm_connector_attach_encoder(connector: &panel_bridge->connector, |
87 | encoder: bridge->encoder); |
88 | |
89 | if (bridge->dev->registered) { |
90 | if (connector->funcs->reset) |
91 | connector->funcs->reset(connector); |
92 | drm_connector_register(connector); |
93 | } |
94 | |
95 | return 0; |
96 | } |
97 | |
98 | static void panel_bridge_detach(struct drm_bridge *bridge) |
99 | { |
100 | struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); |
101 | struct drm_connector *connector = &panel_bridge->connector; |
102 | |
103 | /* |
104 | * Cleanup the connector if we know it was initialized. |
105 | * |
106 | * FIXME: This wouldn't be needed if the panel_bridge structure was |
107 | * allocated with drmm_kzalloc(). This might be tricky since the |
108 | * drm_device pointer can only be retrieved when the bridge is attached. |
109 | */ |
110 | if (connector->dev) |
111 | drm_connector_cleanup(connector); |
112 | } |
113 | |
114 | static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge, |
115 | struct drm_bridge_state *old_bridge_state) |
116 | { |
117 | struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); |
118 | struct drm_atomic_state *atomic_state = old_bridge_state->base.state; |
119 | struct drm_encoder *encoder = bridge->encoder; |
120 | struct drm_crtc *crtc; |
121 | struct drm_crtc_state *old_crtc_state; |
122 | |
123 | crtc = drm_atomic_get_new_crtc_for_encoder(state: atomic_state, encoder); |
124 | if (!crtc) |
125 | return; |
126 | |
127 | old_crtc_state = drm_atomic_get_old_crtc_state(state: atomic_state, crtc); |
128 | if (old_crtc_state && old_crtc_state->self_refresh_active) |
129 | return; |
130 | |
131 | drm_panel_prepare(panel: panel_bridge->panel); |
132 | } |
133 | |
134 | static void panel_bridge_atomic_enable(struct drm_bridge *bridge, |
135 | struct drm_bridge_state *old_bridge_state) |
136 | { |
137 | struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); |
138 | struct drm_atomic_state *atomic_state = old_bridge_state->base.state; |
139 | struct drm_encoder *encoder = bridge->encoder; |
140 | struct drm_crtc *crtc; |
141 | struct drm_crtc_state *old_crtc_state; |
142 | |
143 | crtc = drm_atomic_get_new_crtc_for_encoder(state: atomic_state, encoder); |
144 | if (!crtc) |
145 | return; |
146 | |
147 | old_crtc_state = drm_atomic_get_old_crtc_state(state: atomic_state, crtc); |
148 | if (old_crtc_state && old_crtc_state->self_refresh_active) |
149 | return; |
150 | |
151 | drm_panel_enable(panel: panel_bridge->panel); |
152 | } |
153 | |
154 | static void panel_bridge_atomic_disable(struct drm_bridge *bridge, |
155 | struct drm_bridge_state *old_bridge_state) |
156 | { |
157 | struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); |
158 | struct drm_atomic_state *atomic_state = old_bridge_state->base.state; |
159 | struct drm_encoder *encoder = bridge->encoder; |
160 | struct drm_crtc *crtc; |
161 | struct drm_crtc_state *new_crtc_state; |
162 | |
163 | crtc = drm_atomic_get_old_crtc_for_encoder(state: atomic_state, encoder); |
164 | if (!crtc) |
165 | return; |
166 | |
167 | new_crtc_state = drm_atomic_get_new_crtc_state(state: atomic_state, crtc); |
168 | if (new_crtc_state && new_crtc_state->self_refresh_active) |
169 | return; |
170 | |
171 | drm_panel_disable(panel: panel_bridge->panel); |
172 | } |
173 | |
174 | static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge, |
175 | struct drm_bridge_state *old_bridge_state) |
176 | { |
177 | struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); |
178 | struct drm_atomic_state *atomic_state = old_bridge_state->base.state; |
179 | struct drm_encoder *encoder = bridge->encoder; |
180 | struct drm_crtc *crtc; |
181 | struct drm_crtc_state *new_crtc_state; |
182 | |
183 | crtc = drm_atomic_get_old_crtc_for_encoder(state: atomic_state, encoder); |
184 | if (!crtc) |
185 | return; |
186 | |
187 | new_crtc_state = drm_atomic_get_new_crtc_state(state: atomic_state, crtc); |
188 | if (new_crtc_state && new_crtc_state->self_refresh_active) |
189 | return; |
190 | |
191 | drm_panel_unprepare(panel: panel_bridge->panel); |
192 | } |
193 | |
194 | static int panel_bridge_get_modes(struct drm_bridge *bridge, |
195 | struct drm_connector *connector) |
196 | { |
197 | struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); |
198 | |
199 | return drm_panel_get_modes(panel: panel_bridge->panel, connector); |
200 | } |
201 | |
202 | static void panel_bridge_debugfs_init(struct drm_bridge *bridge, |
203 | struct dentry *root) |
204 | { |
205 | struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge); |
206 | struct drm_panel *panel = panel_bridge->panel; |
207 | |
208 | root = debugfs_create_dir(name: "panel" , parent: root); |
209 | if (panel->funcs->debugfs_init) |
210 | panel->funcs->debugfs_init(panel, root); |
211 | } |
212 | |
213 | static const struct drm_bridge_funcs panel_bridge_bridge_funcs = { |
214 | .attach = panel_bridge_attach, |
215 | .detach = panel_bridge_detach, |
216 | .atomic_pre_enable = panel_bridge_atomic_pre_enable, |
217 | .atomic_enable = panel_bridge_atomic_enable, |
218 | .atomic_disable = panel_bridge_atomic_disable, |
219 | .atomic_post_disable = panel_bridge_atomic_post_disable, |
220 | .get_modes = panel_bridge_get_modes, |
221 | .atomic_reset = drm_atomic_helper_bridge_reset, |
222 | .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, |
223 | .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, |
224 | .atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt, |
225 | .debugfs_init = panel_bridge_debugfs_init, |
226 | }; |
227 | |
228 | /** |
229 | * drm_bridge_is_panel - Checks if a drm_bridge is a panel_bridge. |
230 | * |
231 | * @bridge: The drm_bridge to be checked. |
232 | * |
233 | * Returns true if the bridge is a panel bridge, or false otherwise. |
234 | */ |
235 | bool drm_bridge_is_panel(const struct drm_bridge *bridge) |
236 | { |
237 | return bridge->funcs == &panel_bridge_bridge_funcs; |
238 | } |
239 | EXPORT_SYMBOL(drm_bridge_is_panel); |
240 | |
241 | /** |
242 | * drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that |
243 | * just calls the appropriate functions from &drm_panel. |
244 | * |
245 | * @panel: The drm_panel being wrapped. Must be non-NULL. |
246 | * |
247 | * For drivers converting from directly using drm_panel: The expected |
248 | * usage pattern is that during either encoder module probe or DSI |
249 | * host attach, a drm_panel will be looked up through |
250 | * drm_of_find_panel_or_bridge(). drm_panel_bridge_add() is used to |
251 | * wrap that panel in the new bridge, and the result can then be |
252 | * passed to drm_bridge_attach(). The drm_panel_prepare() and related |
253 | * functions can be dropped from the encoder driver (they're now |
254 | * called by the KMS helpers before calling into the encoder), along |
255 | * with connector creation. When done with the bridge (after |
256 | * drm_mode_config_cleanup() if the bridge has already been attached), then |
257 | * drm_panel_bridge_remove() to free it. |
258 | * |
259 | * The connector type is set to @panel->connector_type, which must be set to a |
260 | * known type. Calling this function with a panel whose connector type is |
261 | * DRM_MODE_CONNECTOR_Unknown will return ERR_PTR(-EINVAL). |
262 | * |
263 | * See devm_drm_panel_bridge_add() for an automatically managed version of this |
264 | * function. |
265 | */ |
266 | struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel) |
267 | { |
268 | if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown)) |
269 | return ERR_PTR(error: -EINVAL); |
270 | |
271 | return drm_panel_bridge_add_typed(panel, connector_type: panel->connector_type); |
272 | } |
273 | EXPORT_SYMBOL(drm_panel_bridge_add); |
274 | |
275 | /** |
276 | * drm_panel_bridge_add_typed - Creates a &drm_bridge and &drm_connector with |
277 | * an explicit connector type. |
278 | * @panel: The drm_panel being wrapped. Must be non-NULL. |
279 | * @connector_type: The connector type (DRM_MODE_CONNECTOR_*) |
280 | * |
281 | * This is just like drm_panel_bridge_add(), but forces the connector type to |
282 | * @connector_type instead of infering it from the panel. |
283 | * |
284 | * This function is deprecated and should not be used in new drivers. Use |
285 | * drm_panel_bridge_add() instead, and fix panel drivers as necessary if they |
286 | * don't report a connector type. |
287 | */ |
288 | struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel, |
289 | u32 connector_type) |
290 | { |
291 | struct panel_bridge *panel_bridge; |
292 | |
293 | if (!panel) |
294 | return ERR_PTR(error: -EINVAL); |
295 | |
296 | panel_bridge = devm_kzalloc(dev: panel->dev, size: sizeof(*panel_bridge), |
297 | GFP_KERNEL); |
298 | if (!panel_bridge) |
299 | return ERR_PTR(error: -ENOMEM); |
300 | |
301 | panel_bridge->connector_type = connector_type; |
302 | panel_bridge->panel = panel; |
303 | |
304 | panel_bridge->bridge.funcs = &panel_bridge_bridge_funcs; |
305 | panel_bridge->bridge.of_node = panel->dev->of_node; |
306 | panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES; |
307 | panel_bridge->bridge.type = connector_type; |
308 | |
309 | drm_bridge_add(bridge: &panel_bridge->bridge); |
310 | |
311 | return &panel_bridge->bridge; |
312 | } |
313 | EXPORT_SYMBOL(drm_panel_bridge_add_typed); |
314 | |
315 | /** |
316 | * drm_panel_bridge_remove - Unregisters and frees a drm_bridge |
317 | * created by drm_panel_bridge_add(). |
318 | * |
319 | * @bridge: The drm_bridge being freed. |
320 | */ |
321 | void drm_panel_bridge_remove(struct drm_bridge *bridge) |
322 | { |
323 | struct panel_bridge *panel_bridge; |
324 | |
325 | if (!bridge) |
326 | return; |
327 | |
328 | if (bridge->funcs != &panel_bridge_bridge_funcs) |
329 | return; |
330 | |
331 | panel_bridge = drm_bridge_to_panel_bridge(bridge); |
332 | |
333 | drm_bridge_remove(bridge); |
334 | devm_kfree(dev: panel_bridge->panel->dev, p: bridge); |
335 | } |
336 | EXPORT_SYMBOL(drm_panel_bridge_remove); |
337 | |
338 | /** |
339 | * drm_panel_bridge_set_orientation - Set the connector's panel orientation |
340 | * from the bridge that can be transformed to panel bridge. |
341 | * |
342 | * @connector: The connector to be set panel orientation. |
343 | * @bridge: The drm_bridge to be transformed to panel bridge. |
344 | * |
345 | * Returns 0 on success, negative errno on failure. |
346 | */ |
347 | int drm_panel_bridge_set_orientation(struct drm_connector *connector, |
348 | struct drm_bridge *bridge) |
349 | { |
350 | struct panel_bridge *panel_bridge; |
351 | |
352 | panel_bridge = drm_bridge_to_panel_bridge(bridge); |
353 | |
354 | return drm_connector_set_orientation_from_panel(connector, |
355 | panel: panel_bridge->panel); |
356 | } |
357 | EXPORT_SYMBOL(drm_panel_bridge_set_orientation); |
358 | |
359 | static void devm_drm_panel_bridge_release(struct device *dev, void *res) |
360 | { |
361 | struct drm_bridge **bridge = res; |
362 | |
363 | drm_panel_bridge_remove(*bridge); |
364 | } |
365 | |
366 | /** |
367 | * devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector |
368 | * that just calls the appropriate functions from &drm_panel. |
369 | * @dev: device to tie the bridge lifetime to |
370 | * @panel: The drm_panel being wrapped. Must be non-NULL. |
371 | * |
372 | * This is the managed version of drm_panel_bridge_add() which automatically |
373 | * calls drm_panel_bridge_remove() when @dev is unbound. |
374 | */ |
375 | struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev, |
376 | struct drm_panel *panel) |
377 | { |
378 | if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown)) |
379 | return ERR_PTR(error: -EINVAL); |
380 | |
381 | return devm_drm_panel_bridge_add_typed(dev, panel, |
382 | connector_type: panel->connector_type); |
383 | } |
384 | EXPORT_SYMBOL(devm_drm_panel_bridge_add); |
385 | |
386 | /** |
387 | * devm_drm_panel_bridge_add_typed - Creates a managed &drm_bridge and |
388 | * &drm_connector with an explicit connector type. |
389 | * @dev: device to tie the bridge lifetime to |
390 | * @panel: The drm_panel being wrapped. Must be non-NULL. |
391 | * @connector_type: The connector type (DRM_MODE_CONNECTOR_*) |
392 | * |
393 | * This is just like devm_drm_panel_bridge_add(), but forces the connector type |
394 | * to @connector_type instead of infering it from the panel. |
395 | * |
396 | * This function is deprecated and should not be used in new drivers. Use |
397 | * devm_drm_panel_bridge_add() instead, and fix panel drivers as necessary if |
398 | * they don't report a connector type. |
399 | */ |
400 | struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev, |
401 | struct drm_panel *panel, |
402 | u32 connector_type) |
403 | { |
404 | struct drm_bridge **ptr, *bridge; |
405 | |
406 | ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr), |
407 | GFP_KERNEL); |
408 | if (!ptr) |
409 | return ERR_PTR(error: -ENOMEM); |
410 | |
411 | bridge = drm_panel_bridge_add_typed(panel, connector_type); |
412 | if (IS_ERR(ptr: bridge)) { |
413 | devres_free(res: ptr); |
414 | return bridge; |
415 | } |
416 | |
417 | bridge->pre_enable_prev_first = panel->prepare_prev_first; |
418 | |
419 | *ptr = bridge; |
420 | devres_add(dev, res: ptr); |
421 | |
422 | return bridge; |
423 | } |
424 | EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed); |
425 | |
426 | static void drmm_drm_panel_bridge_release(struct drm_device *drm, void *ptr) |
427 | { |
428 | struct drm_bridge *bridge = ptr; |
429 | |
430 | drm_panel_bridge_remove(bridge); |
431 | } |
432 | |
433 | /** |
434 | * drmm_panel_bridge_add - Creates a DRM-managed &drm_bridge and |
435 | * &drm_connector that just calls the |
436 | * appropriate functions from &drm_panel. |
437 | * |
438 | * @drm: DRM device to tie the bridge lifetime to |
439 | * @panel: The drm_panel being wrapped. Must be non-NULL. |
440 | * |
441 | * This is the DRM-managed version of drm_panel_bridge_add() which |
442 | * automatically calls drm_panel_bridge_remove() when @dev is cleaned |
443 | * up. |
444 | */ |
445 | struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm, |
446 | struct drm_panel *panel) |
447 | { |
448 | struct drm_bridge *bridge; |
449 | int ret; |
450 | |
451 | bridge = drm_panel_bridge_add_typed(panel, panel->connector_type); |
452 | if (IS_ERR(ptr: bridge)) |
453 | return bridge; |
454 | |
455 | ret = drmm_add_action_or_reset(drm, drmm_drm_panel_bridge_release, |
456 | bridge); |
457 | if (ret) |
458 | return ERR_PTR(error: ret); |
459 | |
460 | bridge->pre_enable_prev_first = panel->prepare_prev_first; |
461 | |
462 | return bridge; |
463 | } |
464 | EXPORT_SYMBOL(drmm_panel_bridge_add); |
465 | |
466 | /** |
467 | * drm_panel_bridge_connector - return the connector for the panel bridge |
468 | * @bridge: The drm_bridge. |
469 | * |
470 | * drm_panel_bridge creates the connector. |
471 | * This function gives external access to the connector. |
472 | * |
473 | * Returns: Pointer to drm_connector |
474 | */ |
475 | struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge) |
476 | { |
477 | struct panel_bridge *panel_bridge; |
478 | |
479 | panel_bridge = drm_bridge_to_panel_bridge(bridge); |
480 | |
481 | return &panel_bridge->connector; |
482 | } |
483 | EXPORT_SYMBOL(drm_panel_bridge_connector); |
484 | |
485 | #ifdef CONFIG_OF |
486 | /** |
487 | * devm_drm_of_get_bridge - Return next bridge in the chain |
488 | * @dev: device to tie the bridge lifetime to |
489 | * @np: device tree node containing encoder output ports |
490 | * @port: port in the device tree node |
491 | * @endpoint: endpoint in the device tree node |
492 | * |
493 | * Given a DT node's port and endpoint number, finds the connected node |
494 | * and returns the associated bridge if any, or creates and returns a |
495 | * drm panel bridge instance if a panel is connected. |
496 | * |
497 | * Returns a pointer to the bridge if successful, or an error pointer |
498 | * otherwise. |
499 | */ |
500 | struct drm_bridge *devm_drm_of_get_bridge(struct device *dev, |
501 | struct device_node *np, |
502 | u32 port, u32 endpoint) |
503 | { |
504 | struct drm_bridge *bridge; |
505 | struct drm_panel *panel; |
506 | int ret; |
507 | |
508 | ret = drm_of_find_panel_or_bridge(np, port, endpoint, |
509 | panel: &panel, bridge: &bridge); |
510 | if (ret) |
511 | return ERR_PTR(error: ret); |
512 | |
513 | if (panel) |
514 | bridge = devm_drm_panel_bridge_add(dev, panel); |
515 | |
516 | return bridge; |
517 | } |
518 | EXPORT_SYMBOL(devm_drm_of_get_bridge); |
519 | |
520 | /** |
521 | * drmm_of_get_bridge - Return next bridge in the chain |
522 | * @drm: device to tie the bridge lifetime to |
523 | * @np: device tree node containing encoder output ports |
524 | * @port: port in the device tree node |
525 | * @endpoint: endpoint in the device tree node |
526 | * |
527 | * Given a DT node's port and endpoint number, finds the connected node |
528 | * and returns the associated bridge if any, or creates and returns a |
529 | * drm panel bridge instance if a panel is connected. |
530 | * |
531 | * Returns a drmm managed pointer to the bridge if successful, or an error |
532 | * pointer otherwise. |
533 | */ |
534 | struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm, |
535 | struct device_node *np, |
536 | u32 port, u32 endpoint) |
537 | { |
538 | struct drm_bridge *bridge; |
539 | struct drm_panel *panel; |
540 | int ret; |
541 | |
542 | ret = drm_of_find_panel_or_bridge(np, port, endpoint, |
543 | panel: &panel, bridge: &bridge); |
544 | if (ret) |
545 | return ERR_PTR(error: ret); |
546 | |
547 | if (panel) |
548 | bridge = drmm_panel_bridge_add(drm, panel); |
549 | |
550 | return bridge; |
551 | } |
552 | EXPORT_SYMBOL(drmm_of_get_bridge); |
553 | |
554 | #endif |
555 | |