Line data Source code
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 0 : 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 0 : return container_of(connector, struct panel_bridge, connector);
35 : }
36 :
37 0 : static int panel_bridge_connector_get_modes(struct drm_connector *connector)
38 : {
39 0 : struct panel_bridge *panel_bridge =
40 : drm_connector_to_panel_bridge(connector);
41 :
42 0 : return drm_panel_get_modes(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 0 : static int panel_bridge_attach(struct drm_bridge *bridge,
59 : enum drm_bridge_attach_flags flags)
60 : {
61 0 : struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
62 0 : struct drm_connector *connector = &panel_bridge->connector;
63 : int ret;
64 :
65 0 : if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
66 : return 0;
67 :
68 0 : if (!bridge->encoder) {
69 0 : DRM_ERROR("Missing encoder\n");
70 0 : return -ENODEV;
71 : }
72 :
73 0 : drm_connector_helper_add(connector,
74 : &panel_bridge_connector_helper_funcs);
75 :
76 0 : ret = drm_connector_init(bridge->dev, connector,
77 : &panel_bridge_connector_funcs,
78 0 : panel_bridge->connector_type);
79 0 : if (ret) {
80 0 : DRM_ERROR("Failed to initialize connector\n");
81 0 : return ret;
82 : }
83 :
84 0 : drm_panel_bridge_set_orientation(connector, bridge);
85 :
86 0 : drm_connector_attach_encoder(&panel_bridge->connector,
87 : bridge->encoder);
88 :
89 0 : if (bridge->dev->registered) {
90 0 : if (connector->funcs->reset)
91 0 : connector->funcs->reset(connector);
92 0 : drm_connector_register(connector);
93 : }
94 :
95 : return 0;
96 : }
97 :
98 0 : static void panel_bridge_detach(struct drm_bridge *bridge)
99 : {
100 0 : struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
101 0 : 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 0 : if (connector->dev)
111 0 : drm_connector_cleanup(connector);
112 0 : }
113 :
114 0 : static void panel_bridge_pre_enable(struct drm_bridge *bridge)
115 : {
116 0 : struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
117 :
118 0 : drm_panel_prepare(panel_bridge->panel);
119 0 : }
120 :
121 0 : static void panel_bridge_enable(struct drm_bridge *bridge)
122 : {
123 0 : struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
124 :
125 0 : drm_panel_enable(panel_bridge->panel);
126 0 : }
127 :
128 0 : static void panel_bridge_disable(struct drm_bridge *bridge)
129 : {
130 0 : struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
131 :
132 0 : drm_panel_disable(panel_bridge->panel);
133 0 : }
134 :
135 0 : static void panel_bridge_post_disable(struct drm_bridge *bridge)
136 : {
137 0 : struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
138 :
139 0 : drm_panel_unprepare(panel_bridge->panel);
140 0 : }
141 :
142 0 : static int panel_bridge_get_modes(struct drm_bridge *bridge,
143 : struct drm_connector *connector)
144 : {
145 0 : struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
146 :
147 0 : return drm_panel_get_modes(panel_bridge->panel, connector);
148 : }
149 :
150 0 : static void panel_bridge_debugfs_init(struct drm_bridge *bridge,
151 : struct dentry *root)
152 : {
153 0 : struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
154 0 : struct drm_panel *panel = panel_bridge->panel;
155 :
156 0 : root = debugfs_create_dir("panel", root);
157 0 : if (panel->funcs->debugfs_init)
158 0 : panel->funcs->debugfs_init(panel, root);
159 0 : }
160 :
161 : static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
162 : .attach = panel_bridge_attach,
163 : .detach = panel_bridge_detach,
164 : .pre_enable = panel_bridge_pre_enable,
165 : .enable = panel_bridge_enable,
166 : .disable = panel_bridge_disable,
167 : .post_disable = panel_bridge_post_disable,
168 : .get_modes = panel_bridge_get_modes,
169 : .atomic_reset = drm_atomic_helper_bridge_reset,
170 : .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
171 : .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
172 : .atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
173 : .debugfs_init = panel_bridge_debugfs_init,
174 : };
175 :
176 : /**
177 : * drm_bridge_is_panel - Checks if a drm_bridge is a panel_bridge.
178 : *
179 : * @bridge: The drm_bridge to be checked.
180 : *
181 : * Returns true if the bridge is a panel bridge, or false otherwise.
182 : */
183 0 : bool drm_bridge_is_panel(const struct drm_bridge *bridge)
184 : {
185 0 : return bridge->funcs == &panel_bridge_bridge_funcs;
186 : }
187 : EXPORT_SYMBOL(drm_bridge_is_panel);
188 :
189 : /**
190 : * drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that
191 : * just calls the appropriate functions from &drm_panel.
192 : *
193 : * @panel: The drm_panel being wrapped. Must be non-NULL.
194 : *
195 : * For drivers converting from directly using drm_panel: The expected
196 : * usage pattern is that during either encoder module probe or DSI
197 : * host attach, a drm_panel will be looked up through
198 : * drm_of_find_panel_or_bridge(). drm_panel_bridge_add() is used to
199 : * wrap that panel in the new bridge, and the result can then be
200 : * passed to drm_bridge_attach(). The drm_panel_prepare() and related
201 : * functions can be dropped from the encoder driver (they're now
202 : * called by the KMS helpers before calling into the encoder), along
203 : * with connector creation. When done with the bridge (after
204 : * drm_mode_config_cleanup() if the bridge has already been attached), then
205 : * drm_panel_bridge_remove() to free it.
206 : *
207 : * The connector type is set to @panel->connector_type, which must be set to a
208 : * known type. Calling this function with a panel whose connector type is
209 : * DRM_MODE_CONNECTOR_Unknown will return ERR_PTR(-EINVAL).
210 : *
211 : * See devm_drm_panel_bridge_add() for an automatically managed version of this
212 : * function.
213 : */
214 0 : struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel)
215 : {
216 0 : if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
217 : return ERR_PTR(-EINVAL);
218 :
219 0 : return drm_panel_bridge_add_typed(panel, panel->connector_type);
220 : }
221 : EXPORT_SYMBOL(drm_panel_bridge_add);
222 :
223 : /**
224 : * drm_panel_bridge_add_typed - Creates a &drm_bridge and &drm_connector with
225 : * an explicit connector type.
226 : * @panel: The drm_panel being wrapped. Must be non-NULL.
227 : * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
228 : *
229 : * This is just like drm_panel_bridge_add(), but forces the connector type to
230 : * @connector_type instead of infering it from the panel.
231 : *
232 : * This function is deprecated and should not be used in new drivers. Use
233 : * drm_panel_bridge_add() instead, and fix panel drivers as necessary if they
234 : * don't report a connector type.
235 : */
236 0 : struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
237 : u32 connector_type)
238 : {
239 : struct panel_bridge *panel_bridge;
240 :
241 0 : if (!panel)
242 : return ERR_PTR(-EINVAL);
243 :
244 0 : panel_bridge = devm_kzalloc(panel->dev, sizeof(*panel_bridge),
245 : GFP_KERNEL);
246 0 : if (!panel_bridge)
247 : return ERR_PTR(-ENOMEM);
248 :
249 0 : panel_bridge->connector_type = connector_type;
250 0 : panel_bridge->panel = panel;
251 :
252 0 : panel_bridge->bridge.funcs = &panel_bridge_bridge_funcs;
253 : #ifdef CONFIG_OF
254 : panel_bridge->bridge.of_node = panel->dev->of_node;
255 : #endif
256 0 : panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES;
257 0 : panel_bridge->bridge.type = connector_type;
258 :
259 0 : drm_bridge_add(&panel_bridge->bridge);
260 :
261 0 : return &panel_bridge->bridge;
262 : }
263 : EXPORT_SYMBOL(drm_panel_bridge_add_typed);
264 :
265 : /**
266 : * drm_panel_bridge_remove - Unregisters and frees a drm_bridge
267 : * created by drm_panel_bridge_add().
268 : *
269 : * @bridge: The drm_bridge being freed.
270 : */
271 0 : void drm_panel_bridge_remove(struct drm_bridge *bridge)
272 : {
273 : struct panel_bridge *panel_bridge;
274 :
275 0 : if (!bridge)
276 : return;
277 :
278 0 : if (bridge->funcs != &panel_bridge_bridge_funcs)
279 : return;
280 :
281 0 : panel_bridge = drm_bridge_to_panel_bridge(bridge);
282 :
283 0 : drm_bridge_remove(bridge);
284 0 : devm_kfree(panel_bridge->panel->dev, bridge);
285 : }
286 : EXPORT_SYMBOL(drm_panel_bridge_remove);
287 :
288 : /**
289 : * drm_panel_bridge_set_orientation - Set the connector's panel orientation
290 : * from the bridge that can be transformed to panel bridge.
291 : *
292 : * @connector: The connector to be set panel orientation.
293 : * @bridge: The drm_bridge to be transformed to panel bridge.
294 : *
295 : * Returns 0 on success, negative errno on failure.
296 : */
297 0 : int drm_panel_bridge_set_orientation(struct drm_connector *connector,
298 : struct drm_bridge *bridge)
299 : {
300 : struct panel_bridge *panel_bridge;
301 :
302 0 : panel_bridge = drm_bridge_to_panel_bridge(bridge);
303 :
304 0 : return drm_connector_set_orientation_from_panel(connector,
305 : panel_bridge->panel);
306 : }
307 : EXPORT_SYMBOL(drm_panel_bridge_set_orientation);
308 :
309 0 : static void devm_drm_panel_bridge_release(struct device *dev, void *res)
310 : {
311 0 : struct drm_bridge **bridge = res;
312 :
313 0 : drm_panel_bridge_remove(*bridge);
314 0 : }
315 :
316 : /**
317 : * devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector
318 : * that just calls the appropriate functions from &drm_panel.
319 : * @dev: device to tie the bridge lifetime to
320 : * @panel: The drm_panel being wrapped. Must be non-NULL.
321 : *
322 : * This is the managed version of drm_panel_bridge_add() which automatically
323 : * calls drm_panel_bridge_remove() when @dev is unbound.
324 : */
325 0 : struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
326 : struct drm_panel *panel)
327 : {
328 0 : if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
329 : return ERR_PTR(-EINVAL);
330 :
331 0 : return devm_drm_panel_bridge_add_typed(dev, panel,
332 0 : panel->connector_type);
333 : }
334 : EXPORT_SYMBOL(devm_drm_panel_bridge_add);
335 :
336 : /**
337 : * devm_drm_panel_bridge_add_typed - Creates a managed &drm_bridge and
338 : * &drm_connector with an explicit connector type.
339 : * @dev: device to tie the bridge lifetime to
340 : * @panel: The drm_panel being wrapped. Must be non-NULL.
341 : * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
342 : *
343 : * This is just like devm_drm_panel_bridge_add(), but forces the connector type
344 : * to @connector_type instead of infering it from the panel.
345 : *
346 : * This function is deprecated and should not be used in new drivers. Use
347 : * devm_drm_panel_bridge_add() instead, and fix panel drivers as necessary if
348 : * they don't report a connector type.
349 : */
350 0 : struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
351 : struct drm_panel *panel,
352 : u32 connector_type)
353 : {
354 : struct drm_bridge **ptr, *bridge;
355 :
356 0 : ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
357 : GFP_KERNEL);
358 0 : if (!ptr)
359 : return ERR_PTR(-ENOMEM);
360 :
361 0 : bridge = drm_panel_bridge_add_typed(panel, connector_type);
362 0 : if (IS_ERR(bridge)) {
363 0 : devres_free(ptr);
364 0 : return bridge;
365 : }
366 :
367 0 : bridge->pre_enable_prev_first = panel->prepare_prev_first;
368 :
369 0 : *ptr = bridge;
370 0 : devres_add(dev, ptr);
371 :
372 0 : return bridge;
373 : }
374 : EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
375 :
376 0 : static void drmm_drm_panel_bridge_release(struct drm_device *drm, void *ptr)
377 : {
378 0 : struct drm_bridge *bridge = ptr;
379 :
380 0 : drm_panel_bridge_remove(bridge);
381 0 : }
382 :
383 : /**
384 : * drmm_panel_bridge_add - Creates a DRM-managed &drm_bridge and
385 : * &drm_connector that just calls the
386 : * appropriate functions from &drm_panel.
387 : *
388 : * @drm: DRM device to tie the bridge lifetime to
389 : * @panel: The drm_panel being wrapped. Must be non-NULL.
390 : *
391 : * This is the DRM-managed version of drm_panel_bridge_add() which
392 : * automatically calls drm_panel_bridge_remove() when @dev is cleaned
393 : * up.
394 : */
395 0 : struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm,
396 : struct drm_panel *panel)
397 : {
398 : struct drm_bridge *bridge;
399 : int ret;
400 :
401 0 : bridge = drm_panel_bridge_add_typed(panel, panel->connector_type);
402 0 : if (IS_ERR(bridge))
403 : return bridge;
404 :
405 0 : ret = drmm_add_action_or_reset(drm, drmm_drm_panel_bridge_release,
406 : bridge);
407 0 : if (ret)
408 0 : return ERR_PTR(ret);
409 :
410 0 : bridge->pre_enable_prev_first = panel->prepare_prev_first;
411 :
412 0 : return bridge;
413 : }
414 : EXPORT_SYMBOL(drmm_panel_bridge_add);
415 :
416 : /**
417 : * drm_panel_bridge_connector - return the connector for the panel bridge
418 : * @bridge: The drm_bridge.
419 : *
420 : * drm_panel_bridge creates the connector.
421 : * This function gives external access to the connector.
422 : *
423 : * Returns: Pointer to drm_connector
424 : */
425 0 : struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge)
426 : {
427 : struct panel_bridge *panel_bridge;
428 :
429 0 : panel_bridge = drm_bridge_to_panel_bridge(bridge);
430 :
431 0 : return &panel_bridge->connector;
432 : }
433 : EXPORT_SYMBOL(drm_panel_bridge_connector);
434 :
435 : #ifdef CONFIG_OF
436 : /**
437 : * devm_drm_of_get_bridge - Return next bridge in the chain
438 : * @dev: device to tie the bridge lifetime to
439 : * @np: device tree node containing encoder output ports
440 : * @port: port in the device tree node
441 : * @endpoint: endpoint in the device tree node
442 : *
443 : * Given a DT node's port and endpoint number, finds the connected node
444 : * and returns the associated bridge if any, or creates and returns a
445 : * drm panel bridge instance if a panel is connected.
446 : *
447 : * Returns a pointer to the bridge if successful, or an error pointer
448 : * otherwise.
449 : */
450 : struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
451 : struct device_node *np,
452 : u32 port, u32 endpoint)
453 : {
454 : struct drm_bridge *bridge;
455 : struct drm_panel *panel;
456 : int ret;
457 :
458 : ret = drm_of_find_panel_or_bridge(np, port, endpoint,
459 : &panel, &bridge);
460 : if (ret)
461 : return ERR_PTR(ret);
462 :
463 : if (panel)
464 : bridge = devm_drm_panel_bridge_add(dev, panel);
465 :
466 : return bridge;
467 : }
468 : EXPORT_SYMBOL(devm_drm_of_get_bridge);
469 :
470 : /**
471 : * drmm_of_get_bridge - Return next bridge in the chain
472 : * @drm: device to tie the bridge lifetime to
473 : * @np: device tree node containing encoder output ports
474 : * @port: port in the device tree node
475 : * @endpoint: endpoint in the device tree node
476 : *
477 : * Given a DT node's port and endpoint number, finds the connected node
478 : * and returns the associated bridge if any, or creates and returns a
479 : * drm panel bridge instance if a panel is connected.
480 : *
481 : * Returns a drmm managed pointer to the bridge if successful, or an error
482 : * pointer otherwise.
483 : */
484 : struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,
485 : struct device_node *np,
486 : u32 port, u32 endpoint)
487 : {
488 : struct drm_bridge *bridge;
489 : struct drm_panel *panel;
490 : int ret;
491 :
492 : ret = drm_of_find_panel_or_bridge(np, port, endpoint,
493 : &panel, &bridge);
494 : if (ret)
495 : return ERR_PTR(ret);
496 :
497 : if (panel)
498 : bridge = drmm_panel_bridge_add(drm, panel);
499 :
500 : return bridge;
501 : }
502 : EXPORT_SYMBOL(drmm_of_get_bridge);
503 :
504 : #endif
|