xref: /dflybsd-src/sys/dev/drm/drm_bridge.c (revision 3f2dd94a569761201b5b0a18b2f697f97fe1b9dc)
119c468b4SFrançois Tigeot /*
219c468b4SFrançois Tigeot  * Copyright (c) 2014 Samsung Electronics Co., Ltd
319c468b4SFrançois Tigeot  *
419c468b4SFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
519c468b4SFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
619c468b4SFrançois Tigeot  * to deal in the Software without restriction, including without limitation
719c468b4SFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sub license,
819c468b4SFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
919c468b4SFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
1019c468b4SFrançois Tigeot  *
1119c468b4SFrançois Tigeot  * The above copyright notice and this permission notice (including the
1219c468b4SFrançois Tigeot  * next paragraph) shall be included in all copies or substantial portions
1319c468b4SFrançois Tigeot  * of the Software.
1419c468b4SFrançois Tigeot  *
1519c468b4SFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1619c468b4SFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1719c468b4SFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
1819c468b4SFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919c468b4SFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2019c468b4SFrançois Tigeot  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2119c468b4SFrançois Tigeot  * DEALINGS IN THE SOFTWARE.
2219c468b4SFrançois Tigeot  */
2319c468b4SFrançois Tigeot 
2419c468b4SFrançois Tigeot #include <linux/err.h>
2519c468b4SFrançois Tigeot #include <linux/module.h>
261dedbd3bSFrançois Tigeot #include <linux/mutex.h>
2719c468b4SFrançois Tigeot 
281dedbd3bSFrançois Tigeot #include <drm/drm_bridge.h>
29a85cb24fSFrançois Tigeot #include <drm/drm_encoder.h>
30a85cb24fSFrançois Tigeot 
31a85cb24fSFrançois Tigeot #include "drm_crtc_internal.h"
3219c468b4SFrançois Tigeot 
3319c468b4SFrançois Tigeot /**
3419c468b4SFrançois Tigeot  * DOC: overview
3519c468b4SFrançois Tigeot  *
36*3f2dd94aSFrançois Tigeot  * &struct drm_bridge represents a device that hangs on to an encoder. These are
37aee94f86SFrançois Tigeot  * handy when a regular &drm_encoder entity isn't enough to represent the entire
3819c468b4SFrançois Tigeot  * encoder chain.
3919c468b4SFrançois Tigeot  *
40aee94f86SFrançois Tigeot  * A bridge is always attached to a single &drm_encoder at a time, but can be
411dedbd3bSFrançois Tigeot  * either connected to it directly, or through an intermediate bridge::
4219c468b4SFrançois Tigeot  *
4319c468b4SFrançois Tigeot  *     encoder ---> bridge B ---> bridge A
4419c468b4SFrançois Tigeot  *
4519c468b4SFrançois Tigeot  * Here, the output of the encoder feeds to bridge B, and that furthers feeds to
4619c468b4SFrançois Tigeot  * bridge A.
4719c468b4SFrançois Tigeot  *
4819c468b4SFrançois Tigeot  * The driver using the bridge is responsible to make the associations between
4919c468b4SFrançois Tigeot  * the encoder and bridges. Once these links are made, the bridges will
5019c468b4SFrançois Tigeot  * participate along with encoder functions to perform mode_set/enable/disable
51aee94f86SFrançois Tigeot  * through the ops provided in &drm_bridge_funcs.
5219c468b4SFrançois Tigeot  *
5319c468b4SFrançois Tigeot  * drm_bridge, like drm_panel, aren't drm_mode_object entities like planes,
54aee94f86SFrançois Tigeot  * CRTCs, encoders or connectors and hence are not visible to userspace. They
55aee94f86SFrançois Tigeot  * just provide additional hooks to get the desired output at the end of the
56aee94f86SFrançois Tigeot  * encoder chain.
57aee94f86SFrançois Tigeot  *
58*3f2dd94aSFrançois Tigeot  * Bridges can also be chained up using the &drm_bridge.next pointer.
59aee94f86SFrançois Tigeot  *
60aee94f86SFrançois Tigeot  * Both legacy CRTC helpers and the new atomic modeset helpers support bridges.
6119c468b4SFrançois Tigeot  */
6219c468b4SFrançois Tigeot 
6319c468b4SFrançois Tigeot static DEFINE_MUTEX(bridge_lock);
6419c468b4SFrançois Tigeot static LINUX_LIST_HEAD(bridge_list);
6519c468b4SFrançois Tigeot 
6619c468b4SFrançois Tigeot /**
6719c468b4SFrançois Tigeot  * drm_bridge_add - add the given bridge to the global bridge list
6819c468b4SFrançois Tigeot  *
6919c468b4SFrançois Tigeot  * @bridge: bridge control structure
7019c468b4SFrançois Tigeot  */
drm_bridge_add(struct drm_bridge * bridge)71*3f2dd94aSFrançois Tigeot void drm_bridge_add(struct drm_bridge *bridge)
7219c468b4SFrançois Tigeot {
7319c468b4SFrançois Tigeot 	mutex_lock(&bridge_lock);
7419c468b4SFrançois Tigeot 	list_add_tail(&bridge->list, &bridge_list);
7519c468b4SFrançois Tigeot 	mutex_unlock(&bridge_lock);
7619c468b4SFrançois Tigeot }
7719c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_add);
7819c468b4SFrançois Tigeot 
7919c468b4SFrançois Tigeot /**
8019c468b4SFrançois Tigeot  * drm_bridge_remove - remove the given bridge from the global bridge list
8119c468b4SFrançois Tigeot  *
8219c468b4SFrançois Tigeot  * @bridge: bridge control structure
8319c468b4SFrançois Tigeot  */
drm_bridge_remove(struct drm_bridge * bridge)8419c468b4SFrançois Tigeot void drm_bridge_remove(struct drm_bridge *bridge)
8519c468b4SFrançois Tigeot {
8619c468b4SFrançois Tigeot 	mutex_lock(&bridge_lock);
8719c468b4SFrançois Tigeot 	list_del_init(&bridge->list);
8819c468b4SFrançois Tigeot 	mutex_unlock(&bridge_lock);
8919c468b4SFrançois Tigeot }
9019c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_remove);
9119c468b4SFrançois Tigeot 
9219c468b4SFrançois Tigeot /**
93a85cb24fSFrançois Tigeot  * drm_bridge_attach - attach the bridge to an encoder's chain
9419c468b4SFrançois Tigeot  *
95a85cb24fSFrançois Tigeot  * @encoder: DRM encoder
96a85cb24fSFrançois Tigeot  * @bridge: bridge to attach
97a85cb24fSFrançois Tigeot  * @previous: previous bridge in the chain (optional)
9819c468b4SFrançois Tigeot  *
99a85cb24fSFrançois Tigeot  * Called by a kms driver to link the bridge to an encoder's chain. The previous
100a85cb24fSFrançois Tigeot  * argument specifies the previous bridge in the chain. If NULL, the bridge is
101a85cb24fSFrançois Tigeot  * linked directly at the encoder's output. Otherwise it is linked at the
102a85cb24fSFrançois Tigeot  * previous bridge's output.
10319c468b4SFrançois Tigeot  *
104a85cb24fSFrançois Tigeot  * If non-NULL the previous bridge must be already attached by a call to this
105a85cb24fSFrançois Tigeot  * function.
10619c468b4SFrançois Tigeot  *
10719c468b4SFrançois Tigeot  * RETURNS:
10819c468b4SFrançois Tigeot  * Zero on success, error code on failure
10919c468b4SFrançois Tigeot  */
drm_bridge_attach(struct drm_encoder * encoder,struct drm_bridge * bridge,struct drm_bridge * previous)110a85cb24fSFrançois Tigeot int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
111a85cb24fSFrançois Tigeot 		      struct drm_bridge *previous)
11219c468b4SFrançois Tigeot {
113a85cb24fSFrançois Tigeot 	int ret;
114a85cb24fSFrançois Tigeot 
115a85cb24fSFrançois Tigeot 	if (!encoder || !bridge)
116a85cb24fSFrançois Tigeot 		return -EINVAL;
117a85cb24fSFrançois Tigeot 
118a85cb24fSFrançois Tigeot 	if (previous && (!previous->dev || previous->encoder != encoder))
11919c468b4SFrançois Tigeot 		return -EINVAL;
12019c468b4SFrançois Tigeot 
12119c468b4SFrançois Tigeot 	if (bridge->dev)
12219c468b4SFrançois Tigeot 		return -EBUSY;
12319c468b4SFrançois Tigeot 
124a85cb24fSFrançois Tigeot 	bridge->dev = encoder->dev;
125a85cb24fSFrançois Tigeot 	bridge->encoder = encoder;
12619c468b4SFrançois Tigeot 
127a85cb24fSFrançois Tigeot 	if (bridge->funcs->attach) {
128a85cb24fSFrançois Tigeot 		ret = bridge->funcs->attach(bridge);
129a85cb24fSFrançois Tigeot 		if (ret < 0) {
130a85cb24fSFrançois Tigeot 			bridge->dev = NULL;
131a85cb24fSFrançois Tigeot 			bridge->encoder = NULL;
132a85cb24fSFrançois Tigeot 			return ret;
133a85cb24fSFrançois Tigeot 		}
134a85cb24fSFrançois Tigeot 	}
135a85cb24fSFrançois Tigeot 
136a85cb24fSFrançois Tigeot 	if (previous)
137a85cb24fSFrançois Tigeot 		previous->next = bridge;
138a85cb24fSFrançois Tigeot 	else
139a85cb24fSFrançois Tigeot 		encoder->bridge = bridge;
14019c468b4SFrançois Tigeot 
14119c468b4SFrançois Tigeot 	return 0;
14219c468b4SFrançois Tigeot }
14319c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_attach);
14419c468b4SFrançois Tigeot 
drm_bridge_detach(struct drm_bridge * bridge)1451dedbd3bSFrançois Tigeot void drm_bridge_detach(struct drm_bridge *bridge)
1461dedbd3bSFrançois Tigeot {
1471dedbd3bSFrançois Tigeot 	if (WARN_ON(!bridge))
1481dedbd3bSFrançois Tigeot 		return;
1491dedbd3bSFrançois Tigeot 
1501dedbd3bSFrançois Tigeot 	if (WARN_ON(!bridge->dev))
1511dedbd3bSFrançois Tigeot 		return;
1521dedbd3bSFrançois Tigeot 
1531dedbd3bSFrançois Tigeot 	if (bridge->funcs->detach)
1541dedbd3bSFrançois Tigeot 		bridge->funcs->detach(bridge);
1551dedbd3bSFrançois Tigeot 
1561dedbd3bSFrançois Tigeot 	bridge->dev = NULL;
1571dedbd3bSFrançois Tigeot }
1581dedbd3bSFrançois Tigeot 
1591dedbd3bSFrançois Tigeot /**
16019c468b4SFrançois Tigeot  * DOC: bridge callbacks
16119c468b4SFrançois Tigeot  *
162aee94f86SFrançois Tigeot  * The &drm_bridge_funcs ops are populated by the bridge driver. The DRM
163aee94f86SFrançois Tigeot  * internals (atomic and CRTC helpers) use the helpers defined in drm_bridge.c
164aee94f86SFrançois Tigeot  * These helpers call a specific &drm_bridge_funcs op for all the bridges
16519c468b4SFrançois Tigeot  * during encoder configuration.
16619c468b4SFrançois Tigeot  *
167aee94f86SFrançois Tigeot  * For detailed specification of the bridge callbacks see &drm_bridge_funcs.
16819c468b4SFrançois Tigeot  */
16919c468b4SFrançois Tigeot 
17019c468b4SFrançois Tigeot /**
17119c468b4SFrançois Tigeot  * drm_bridge_mode_fixup - fixup proposed mode for all bridges in the
17219c468b4SFrançois Tigeot  *			   encoder chain
17319c468b4SFrançois Tigeot  * @bridge: bridge control structure
17419c468b4SFrançois Tigeot  * @mode: desired mode to be set for the bridge
17519c468b4SFrançois Tigeot  * @adjusted_mode: updated mode that works for this bridge
17619c468b4SFrançois Tigeot  *
177*3f2dd94aSFrançois Tigeot  * Calls &drm_bridge_funcs.mode_fixup for all the bridges in the
17819c468b4SFrançois Tigeot  * encoder chain, starting from the first bridge to the last.
17919c468b4SFrançois Tigeot  *
18019c468b4SFrançois Tigeot  * Note: the bridge passed should be the one closest to the encoder
18119c468b4SFrançois Tigeot  *
18219c468b4SFrançois Tigeot  * RETURNS:
18319c468b4SFrançois Tigeot  * true on success, false on failure
18419c468b4SFrançois Tigeot  */
drm_bridge_mode_fixup(struct drm_bridge * bridge,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)18519c468b4SFrançois Tigeot bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
18619c468b4SFrançois Tigeot 			const struct drm_display_mode *mode,
18719c468b4SFrançois Tigeot 			struct drm_display_mode *adjusted_mode)
18819c468b4SFrançois Tigeot {
18919c468b4SFrançois Tigeot 	bool ret = true;
19019c468b4SFrançois Tigeot 
19119c468b4SFrançois Tigeot 	if (!bridge)
19219c468b4SFrançois Tigeot 		return true;
19319c468b4SFrançois Tigeot 
19419c468b4SFrançois Tigeot 	if (bridge->funcs->mode_fixup)
19519c468b4SFrançois Tigeot 		ret = bridge->funcs->mode_fixup(bridge, mode, adjusted_mode);
19619c468b4SFrançois Tigeot 
19719c468b4SFrançois Tigeot 	ret = ret && drm_bridge_mode_fixup(bridge->next, mode, adjusted_mode);
19819c468b4SFrançois Tigeot 
19919c468b4SFrançois Tigeot 	return ret;
20019c468b4SFrançois Tigeot }
20119c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_mode_fixup);
20219c468b4SFrançois Tigeot 
20319c468b4SFrançois Tigeot /**
204*3f2dd94aSFrançois Tigeot  * drm_bridge_mode_valid - validate the mode against all bridges in the
205*3f2dd94aSFrançois Tigeot  * 			   encoder chain.
206*3f2dd94aSFrançois Tigeot  * @bridge: bridge control structure
207*3f2dd94aSFrançois Tigeot  * @mode: desired mode to be validated
208*3f2dd94aSFrançois Tigeot  *
209*3f2dd94aSFrançois Tigeot  * Calls &drm_bridge_funcs.mode_valid for all the bridges in the encoder
210*3f2dd94aSFrançois Tigeot  * chain, starting from the first bridge to the last. If at least one bridge
211*3f2dd94aSFrançois Tigeot  * does not accept the mode the function returns the error code.
212*3f2dd94aSFrançois Tigeot  *
213*3f2dd94aSFrançois Tigeot  * Note: the bridge passed should be the one closest to the encoder.
214*3f2dd94aSFrançois Tigeot  *
215*3f2dd94aSFrançois Tigeot  * RETURNS:
216*3f2dd94aSFrançois Tigeot  * MODE_OK on success, drm_mode_status Enum error code on failure
217*3f2dd94aSFrançois Tigeot  */
drm_bridge_mode_valid(struct drm_bridge * bridge,const struct drm_display_mode * mode)218*3f2dd94aSFrançois Tigeot enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge,
219*3f2dd94aSFrançois Tigeot 					   const struct drm_display_mode *mode)
220*3f2dd94aSFrançois Tigeot {
221*3f2dd94aSFrançois Tigeot 	enum drm_mode_status ret = MODE_OK;
222*3f2dd94aSFrançois Tigeot 
223*3f2dd94aSFrançois Tigeot 	if (!bridge)
224*3f2dd94aSFrançois Tigeot 		return ret;
225*3f2dd94aSFrançois Tigeot 
226*3f2dd94aSFrançois Tigeot 	if (bridge->funcs->mode_valid)
227*3f2dd94aSFrançois Tigeot 		ret = bridge->funcs->mode_valid(bridge, mode);
228*3f2dd94aSFrançois Tigeot 
229*3f2dd94aSFrançois Tigeot 	if (ret != MODE_OK)
230*3f2dd94aSFrançois Tigeot 		return ret;
231*3f2dd94aSFrançois Tigeot 
232*3f2dd94aSFrançois Tigeot 	return drm_bridge_mode_valid(bridge->next, mode);
233*3f2dd94aSFrançois Tigeot }
234*3f2dd94aSFrançois Tigeot EXPORT_SYMBOL(drm_bridge_mode_valid);
235*3f2dd94aSFrançois Tigeot 
236*3f2dd94aSFrançois Tigeot /**
237*3f2dd94aSFrançois Tigeot  * drm_bridge_disable - disables all bridges in the encoder chain
23819c468b4SFrançois Tigeot  * @bridge: bridge control structure
23919c468b4SFrançois Tigeot  *
240*3f2dd94aSFrançois Tigeot  * Calls &drm_bridge_funcs.disable op for all the bridges in the encoder
24119c468b4SFrançois Tigeot  * chain, starting from the last bridge to the first. These are called before
24219c468b4SFrançois Tigeot  * calling the encoder's prepare op.
24319c468b4SFrançois Tigeot  *
24419c468b4SFrançois Tigeot  * Note: the bridge passed should be the one closest to the encoder
24519c468b4SFrançois Tigeot  */
drm_bridge_disable(struct drm_bridge * bridge)24619c468b4SFrançois Tigeot void drm_bridge_disable(struct drm_bridge *bridge)
24719c468b4SFrançois Tigeot {
24819c468b4SFrançois Tigeot 	if (!bridge)
24919c468b4SFrançois Tigeot 		return;
25019c468b4SFrançois Tigeot 
25119c468b4SFrançois Tigeot 	drm_bridge_disable(bridge->next);
25219c468b4SFrançois Tigeot 
253c0e85e96SFrançois Tigeot 	if (bridge->funcs->disable)
25419c468b4SFrançois Tigeot 		bridge->funcs->disable(bridge);
25519c468b4SFrançois Tigeot }
25619c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_disable);
25719c468b4SFrançois Tigeot 
25819c468b4SFrançois Tigeot /**
259*3f2dd94aSFrançois Tigeot  * drm_bridge_post_disable - cleans up after disabling all bridges in the encoder chain
26019c468b4SFrançois Tigeot  * @bridge: bridge control structure
26119c468b4SFrançois Tigeot  *
262*3f2dd94aSFrançois Tigeot  * Calls &drm_bridge_funcs.post_disable op for all the bridges in the
26319c468b4SFrançois Tigeot  * encoder chain, starting from the first bridge to the last. These are called
26419c468b4SFrançois Tigeot  * after completing the encoder's prepare op.
26519c468b4SFrançois Tigeot  *
26619c468b4SFrançois Tigeot  * Note: the bridge passed should be the one closest to the encoder
26719c468b4SFrançois Tigeot  */
drm_bridge_post_disable(struct drm_bridge * bridge)26819c468b4SFrançois Tigeot void drm_bridge_post_disable(struct drm_bridge *bridge)
26919c468b4SFrançois Tigeot {
27019c468b4SFrançois Tigeot 	if (!bridge)
27119c468b4SFrançois Tigeot 		return;
27219c468b4SFrançois Tigeot 
273c0e85e96SFrançois Tigeot 	if (bridge->funcs->post_disable)
27419c468b4SFrançois Tigeot 		bridge->funcs->post_disable(bridge);
27519c468b4SFrançois Tigeot 
27619c468b4SFrançois Tigeot 	drm_bridge_post_disable(bridge->next);
27719c468b4SFrançois Tigeot }
27819c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_post_disable);
27919c468b4SFrançois Tigeot 
28019c468b4SFrançois Tigeot /**
28119c468b4SFrançois Tigeot  * drm_bridge_mode_set - set proposed mode for all bridges in the
28219c468b4SFrançois Tigeot  *			 encoder chain
28319c468b4SFrançois Tigeot  * @bridge: bridge control structure
28419c468b4SFrançois Tigeot  * @mode: desired mode to be set for the bridge
28519c468b4SFrançois Tigeot  * @adjusted_mode: updated mode that works for this bridge
28619c468b4SFrançois Tigeot  *
287*3f2dd94aSFrançois Tigeot  * Calls &drm_bridge_funcs.mode_set op for all the bridges in the
28819c468b4SFrançois Tigeot  * encoder chain, starting from the first bridge to the last.
28919c468b4SFrançois Tigeot  *
29019c468b4SFrançois Tigeot  * Note: the bridge passed should be the one closest to the encoder
29119c468b4SFrançois Tigeot  */
drm_bridge_mode_set(struct drm_bridge * bridge,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)29219c468b4SFrançois Tigeot void drm_bridge_mode_set(struct drm_bridge *bridge,
29319c468b4SFrançois Tigeot 			struct drm_display_mode *mode,
29419c468b4SFrançois Tigeot 			struct drm_display_mode *adjusted_mode)
29519c468b4SFrançois Tigeot {
29619c468b4SFrançois Tigeot 	if (!bridge)
29719c468b4SFrançois Tigeot 		return;
29819c468b4SFrançois Tigeot 
29919c468b4SFrançois Tigeot 	if (bridge->funcs->mode_set)
30019c468b4SFrançois Tigeot 		bridge->funcs->mode_set(bridge, mode, adjusted_mode);
30119c468b4SFrançois Tigeot 
30219c468b4SFrançois Tigeot 	drm_bridge_mode_set(bridge->next, mode, adjusted_mode);
30319c468b4SFrançois Tigeot }
30419c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_mode_set);
30519c468b4SFrançois Tigeot 
30619c468b4SFrançois Tigeot /**
307*3f2dd94aSFrançois Tigeot  * drm_bridge_pre_enable - prepares for enabling all
308*3f2dd94aSFrançois Tigeot  *			   bridges in the encoder chain
30919c468b4SFrançois Tigeot  * @bridge: bridge control structure
31019c468b4SFrançois Tigeot  *
311*3f2dd94aSFrançois Tigeot  * Calls &drm_bridge_funcs.pre_enable op for all the bridges in the encoder
31219c468b4SFrançois Tigeot  * chain, starting from the last bridge to the first. These are called
31319c468b4SFrançois Tigeot  * before calling the encoder's commit op.
31419c468b4SFrançois Tigeot  *
31519c468b4SFrançois Tigeot  * Note: the bridge passed should be the one closest to the encoder
31619c468b4SFrançois Tigeot  */
drm_bridge_pre_enable(struct drm_bridge * bridge)31719c468b4SFrançois Tigeot void drm_bridge_pre_enable(struct drm_bridge *bridge)
31819c468b4SFrançois Tigeot {
31919c468b4SFrançois Tigeot 	if (!bridge)
32019c468b4SFrançois Tigeot 		return;
32119c468b4SFrançois Tigeot 
32219c468b4SFrançois Tigeot 	drm_bridge_pre_enable(bridge->next);
32319c468b4SFrançois Tigeot 
324c0e85e96SFrançois Tigeot 	if (bridge->funcs->pre_enable)
32519c468b4SFrançois Tigeot 		bridge->funcs->pre_enable(bridge);
32619c468b4SFrançois Tigeot }
32719c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_pre_enable);
32819c468b4SFrançois Tigeot 
32919c468b4SFrançois Tigeot /**
330*3f2dd94aSFrançois Tigeot  * drm_bridge_enable - enables all bridges in the encoder chain
33119c468b4SFrançois Tigeot  * @bridge: bridge control structure
33219c468b4SFrançois Tigeot  *
333*3f2dd94aSFrançois Tigeot  * Calls &drm_bridge_funcs.enable op for all the bridges in the encoder
33419c468b4SFrançois Tigeot  * chain, starting from the first bridge to the last. These are called
33519c468b4SFrançois Tigeot  * after completing the encoder's commit op.
33619c468b4SFrançois Tigeot  *
33719c468b4SFrançois Tigeot  * Note that the bridge passed should be the one closest to the encoder
33819c468b4SFrançois Tigeot  */
drm_bridge_enable(struct drm_bridge * bridge)33919c468b4SFrançois Tigeot void drm_bridge_enable(struct drm_bridge *bridge)
34019c468b4SFrançois Tigeot {
34119c468b4SFrançois Tigeot 	if (!bridge)
34219c468b4SFrançois Tigeot 		return;
34319c468b4SFrançois Tigeot 
344c0e85e96SFrançois Tigeot 	if (bridge->funcs->enable)
34519c468b4SFrançois Tigeot 		bridge->funcs->enable(bridge);
34619c468b4SFrançois Tigeot 
34719c468b4SFrançois Tigeot 	drm_bridge_enable(bridge->next);
34819c468b4SFrançois Tigeot }
34919c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_enable);
35019c468b4SFrançois Tigeot 
35119c468b4SFrançois Tigeot #ifdef CONFIG_OF
35219c468b4SFrançois Tigeot /**
35319c468b4SFrançois Tigeot  * of_drm_find_bridge - find the bridge corresponding to the device node in
35419c468b4SFrançois Tigeot  *			the global bridge list
35519c468b4SFrançois Tigeot  *
35619c468b4SFrançois Tigeot  * @np: device node
35719c468b4SFrançois Tigeot  *
35819c468b4SFrançois Tigeot  * RETURNS:
35919c468b4SFrançois Tigeot  * drm_bridge control struct on success, NULL on failure
36019c468b4SFrançois Tigeot  */
of_drm_find_bridge(struct device_node * np)36119c468b4SFrançois Tigeot struct drm_bridge *of_drm_find_bridge(struct device_node *np)
36219c468b4SFrançois Tigeot {
36319c468b4SFrançois Tigeot 	struct drm_bridge *bridge;
36419c468b4SFrançois Tigeot 
36519c468b4SFrançois Tigeot 	mutex_lock(&bridge_lock);
36619c468b4SFrançois Tigeot 
36719c468b4SFrançois Tigeot 	list_for_each_entry(bridge, &bridge_list, list) {
36819c468b4SFrançois Tigeot 		if (bridge->of_node == np) {
36919c468b4SFrançois Tigeot 			mutex_unlock(&bridge_lock);
37019c468b4SFrançois Tigeot 			return bridge;
37119c468b4SFrançois Tigeot 		}
37219c468b4SFrançois Tigeot 	}
37319c468b4SFrançois Tigeot 
37419c468b4SFrançois Tigeot 	mutex_unlock(&bridge_lock);
37519c468b4SFrançois Tigeot 	return NULL;
37619c468b4SFrançois Tigeot }
37719c468b4SFrançois Tigeot EXPORT_SYMBOL(of_drm_find_bridge);
37819c468b4SFrançois Tigeot #endif
37919c468b4SFrançois Tigeot 
38019c468b4SFrançois Tigeot MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>");
38119c468b4SFrançois Tigeot MODULE_DESCRIPTION("DRM bridge infrastructure");
382