xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/drm_bridge.c (revision 41ec02673d281bbb3d38e6c78504ce6e30c228c1)
1*41ec0267Sriastradh /*	$NetBSD: drm_bridge.c,v 1.5 2021/12/18 23:44:57 riastradh Exp $	*/
2efa246c0Sriastradh 
3efa246c0Sriastradh /*
4efa246c0Sriastradh  * Copyright (c) 2014 Samsung Electronics Co., Ltd
5efa246c0Sriastradh  *
6efa246c0Sriastradh  * Permission is hereby granted, free of charge, to any person obtaining a
7efa246c0Sriastradh  * copy of this software and associated documentation files (the "Software"),
8efa246c0Sriastradh  * to deal in the Software without restriction, including without limitation
9efa246c0Sriastradh  * the rights to use, copy, modify, merge, publish, distribute, sub license,
10efa246c0Sriastradh  * and/or sell copies of the Software, and to permit persons to whom the
11efa246c0Sriastradh  * Software is furnished to do so, subject to the following conditions:
12efa246c0Sriastradh  *
13efa246c0Sriastradh  * The above copyright notice and this permission notice (including the
14efa246c0Sriastradh  * next paragraph) shall be included in all copies or substantial portions
15efa246c0Sriastradh  * of the Software.
16efa246c0Sriastradh  *
17efa246c0Sriastradh  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18efa246c0Sriastradh  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19efa246c0Sriastradh  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20efa246c0Sriastradh  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21efa246c0Sriastradh  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22efa246c0Sriastradh  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23efa246c0Sriastradh  * DEALINGS IN THE SOFTWARE.
24efa246c0Sriastradh  */
25efa246c0Sriastradh 
26efa246c0Sriastradh #include <sys/cdefs.h>
27*41ec0267Sriastradh __KERNEL_RCSID(0, "$NetBSD: drm_bridge.c,v 1.5 2021/12/18 23:44:57 riastradh Exp $");
28efa246c0Sriastradh 
29efa246c0Sriastradh #include <linux/err.h>
30efa246c0Sriastradh #include <linux/module.h>
31*41ec0267Sriastradh #include <linux/mutex.h>
32efa246c0Sriastradh 
33*41ec0267Sriastradh #include <drm/drm_bridge.h>
34*41ec0267Sriastradh #include <drm/drm_encoder.h>
35efa246c0Sriastradh 
36*41ec0267Sriastradh #include "drm_crtc_internal.h"
37efa246c0Sriastradh 
38efa246c0Sriastradh /**
39efa246c0Sriastradh  * DOC: overview
40efa246c0Sriastradh  *
41*41ec0267Sriastradh  * &struct drm_bridge represents a device that hangs on to an encoder. These are
42*41ec0267Sriastradh  * handy when a regular &drm_encoder entity isn't enough to represent the entire
43efa246c0Sriastradh  * encoder chain.
44efa246c0Sriastradh  *
45*41ec0267Sriastradh  * A bridge is always attached to a single &drm_encoder at a time, but can be
46*41ec0267Sriastradh  * either connected to it directly, or through an intermediate bridge::
47efa246c0Sriastradh  *
48efa246c0Sriastradh  *     encoder ---> bridge B ---> bridge A
49efa246c0Sriastradh  *
50efa246c0Sriastradh  * Here, the output of the encoder feeds to bridge B, and that furthers feeds to
51efa246c0Sriastradh  * bridge A.
52efa246c0Sriastradh  *
53efa246c0Sriastradh  * The driver using the bridge is responsible to make the associations between
54efa246c0Sriastradh  * the encoder and bridges. Once these links are made, the bridges will
55efa246c0Sriastradh  * participate along with encoder functions to perform mode_set/enable/disable
56*41ec0267Sriastradh  * through the ops provided in &drm_bridge_funcs.
57efa246c0Sriastradh  *
58efa246c0Sriastradh  * drm_bridge, like drm_panel, aren't drm_mode_object entities like planes,
59*41ec0267Sriastradh  * CRTCs, encoders or connectors and hence are not visible to userspace. They
60*41ec0267Sriastradh  * just provide additional hooks to get the desired output at the end of the
61*41ec0267Sriastradh  * encoder chain.
62*41ec0267Sriastradh  *
63*41ec0267Sriastradh  * Bridges can also be chained up using the &drm_bridge.chain_node field.
64*41ec0267Sriastradh  *
65*41ec0267Sriastradh  * Both legacy CRTC helpers and the new atomic modeset helpers support bridges.
66efa246c0Sriastradh  */
67efa246c0Sriastradh 
68eb41e3faSriastradh #ifdef __NetBSD__
69eb41e3faSriastradh static struct mutex bridge_lock;
70eb41e3faSriastradh static struct list_head bridge_list = LIST_HEAD_INIT(bridge_list);
71eb41e3faSriastradh #else
72efa246c0Sriastradh static DEFINE_MUTEX(bridge_lock);
73efa246c0Sriastradh static LIST_HEAD(bridge_list);
74eb41e3faSriastradh #endif
75efa246c0Sriastradh 
76453c4aa9Sjmcneill #ifdef __NetBSD__
drm_bridge_init_lock(void)77453c4aa9Sjmcneill void drm_bridge_init_lock(void)
78453c4aa9Sjmcneill {
79453c4aa9Sjmcneill 	linux_mutex_init(&bridge_lock);
80453c4aa9Sjmcneill }
drm_bridge_fini_lock(void)81453c4aa9Sjmcneill void drm_bridge_fini_lock(void)
82453c4aa9Sjmcneill {
83453c4aa9Sjmcneill 	linux_mutex_destroy(&bridge_lock);
84453c4aa9Sjmcneill }
85453c4aa9Sjmcneill #endif
86453c4aa9Sjmcneill 
87efa246c0Sriastradh /**
88efa246c0Sriastradh  * drm_bridge_add - add the given bridge to the global bridge list
89efa246c0Sriastradh  *
90efa246c0Sriastradh  * @bridge: bridge control structure
91efa246c0Sriastradh  */
drm_bridge_add(struct drm_bridge * bridge)92*41ec0267Sriastradh void drm_bridge_add(struct drm_bridge *bridge)
93efa246c0Sriastradh {
94efa246c0Sriastradh 	mutex_lock(&bridge_lock);
95efa246c0Sriastradh 	list_add_tail(&bridge->list, &bridge_list);
96efa246c0Sriastradh 	mutex_unlock(&bridge_lock);
97efa246c0Sriastradh }
98efa246c0Sriastradh EXPORT_SYMBOL(drm_bridge_add);
99efa246c0Sriastradh 
100efa246c0Sriastradh /**
101efa246c0Sriastradh  * drm_bridge_remove - remove the given bridge from the global bridge list
102efa246c0Sriastradh  *
103efa246c0Sriastradh  * @bridge: bridge control structure
104efa246c0Sriastradh  */
drm_bridge_remove(struct drm_bridge * bridge)105efa246c0Sriastradh void drm_bridge_remove(struct drm_bridge *bridge)
106efa246c0Sriastradh {
107efa246c0Sriastradh 	mutex_lock(&bridge_lock);
108efa246c0Sriastradh 	list_del_init(&bridge->list);
109efa246c0Sriastradh 	mutex_unlock(&bridge_lock);
110efa246c0Sriastradh }
111efa246c0Sriastradh EXPORT_SYMBOL(drm_bridge_remove);
112efa246c0Sriastradh 
113efa246c0Sriastradh /**
114*41ec0267Sriastradh  * drm_bridge_attach - attach the bridge to an encoder's chain
115efa246c0Sriastradh  *
116*41ec0267Sriastradh  * @encoder: DRM encoder
117*41ec0267Sriastradh  * @bridge: bridge to attach
118*41ec0267Sriastradh  * @previous: previous bridge in the chain (optional)
119efa246c0Sriastradh  *
120*41ec0267Sriastradh  * Called by a kms driver to link the bridge to an encoder's chain. The previous
121*41ec0267Sriastradh  * argument specifies the previous bridge in the chain. If NULL, the bridge is
122*41ec0267Sriastradh  * linked directly at the encoder's output. Otherwise it is linked at the
123*41ec0267Sriastradh  * previous bridge's output.
124efa246c0Sriastradh  *
125*41ec0267Sriastradh  * If non-NULL the previous bridge must be already attached by a call to this
126*41ec0267Sriastradh  * function.
127*41ec0267Sriastradh  *
128*41ec0267Sriastradh  * Note that bridges attached to encoders are auto-detached during encoder
129*41ec0267Sriastradh  * cleanup in drm_encoder_cleanup(), so drm_bridge_attach() should generally
130*41ec0267Sriastradh  * *not* be balanced with a drm_bridge_detach() in driver code.
131efa246c0Sriastradh  *
132efa246c0Sriastradh  * RETURNS:
133efa246c0Sriastradh  * Zero on success, error code on failure
134efa246c0Sriastradh  */
drm_bridge_attach(struct drm_encoder * encoder,struct drm_bridge * bridge,struct drm_bridge * previous)135*41ec0267Sriastradh int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
136*41ec0267Sriastradh 		      struct drm_bridge *previous)
137efa246c0Sriastradh {
138*41ec0267Sriastradh 	int ret;
139*41ec0267Sriastradh 
140*41ec0267Sriastradh 	if (!encoder || !bridge)
141*41ec0267Sriastradh 		return -EINVAL;
142*41ec0267Sriastradh 
143*41ec0267Sriastradh 	if (previous && (!previous->dev || previous->encoder != encoder))
144efa246c0Sriastradh 		return -EINVAL;
145efa246c0Sriastradh 
146efa246c0Sriastradh 	if (bridge->dev)
147efa246c0Sriastradh 		return -EBUSY;
148efa246c0Sriastradh 
149*41ec0267Sriastradh 	bridge->dev = encoder->dev;
150*41ec0267Sriastradh 	bridge->encoder = encoder;
151efa246c0Sriastradh 
152*41ec0267Sriastradh 	if (previous)
153*41ec0267Sriastradh 		list_add(&bridge->chain_node, &previous->chain_node);
154*41ec0267Sriastradh 	else
155*41ec0267Sriastradh 		list_add(&bridge->chain_node, &encoder->bridge_chain);
156*41ec0267Sriastradh 
157*41ec0267Sriastradh 	if (bridge->funcs->attach) {
158*41ec0267Sriastradh 		ret = bridge->funcs->attach(bridge);
159*41ec0267Sriastradh 		if (ret < 0) {
160*41ec0267Sriastradh 			list_del(&bridge->chain_node);
161*41ec0267Sriastradh 			bridge->dev = NULL;
162*41ec0267Sriastradh 			bridge->encoder = NULL;
163*41ec0267Sriastradh 			return ret;
164*41ec0267Sriastradh 		}
165*41ec0267Sriastradh 	}
166efa246c0Sriastradh 
167efa246c0Sriastradh 	return 0;
168efa246c0Sriastradh }
169efa246c0Sriastradh EXPORT_SYMBOL(drm_bridge_attach);
170efa246c0Sriastradh 
drm_bridge_detach(struct drm_bridge * bridge)171*41ec0267Sriastradh void drm_bridge_detach(struct drm_bridge *bridge)
172*41ec0267Sriastradh {
173*41ec0267Sriastradh 	if (WARN_ON(!bridge))
174*41ec0267Sriastradh 		return;
175*41ec0267Sriastradh 
176*41ec0267Sriastradh 	if (WARN_ON(!bridge->dev))
177*41ec0267Sriastradh 		return;
178*41ec0267Sriastradh 
179*41ec0267Sriastradh 	if (bridge->funcs->detach)
180*41ec0267Sriastradh 		bridge->funcs->detach(bridge);
181*41ec0267Sriastradh 
182*41ec0267Sriastradh 	list_del(&bridge->chain_node);
183*41ec0267Sriastradh 	bridge->dev = NULL;
184*41ec0267Sriastradh }
185*41ec0267Sriastradh 
186efa246c0Sriastradh /**
187efa246c0Sriastradh  * DOC: bridge callbacks
188efa246c0Sriastradh  *
189*41ec0267Sriastradh  * The &drm_bridge_funcs ops are populated by the bridge driver. The DRM
190*41ec0267Sriastradh  * internals (atomic and CRTC helpers) use the helpers defined in drm_bridge.c
191*41ec0267Sriastradh  * These helpers call a specific &drm_bridge_funcs op for all the bridges
192efa246c0Sriastradh  * during encoder configuration.
193efa246c0Sriastradh  *
194*41ec0267Sriastradh  * For detailed specification of the bridge callbacks see &drm_bridge_funcs.
195efa246c0Sriastradh  */
196efa246c0Sriastradh 
197efa246c0Sriastradh /**
198*41ec0267Sriastradh  * drm_bridge_chain_mode_fixup - fixup proposed mode for all bridges in the
199efa246c0Sriastradh  *				 encoder chain
200efa246c0Sriastradh  * @bridge: bridge control structure
201efa246c0Sriastradh  * @mode: desired mode to be set for the bridge
202efa246c0Sriastradh  * @adjusted_mode: updated mode that works for this bridge
203efa246c0Sriastradh  *
204*41ec0267Sriastradh  * Calls &drm_bridge_funcs.mode_fixup for all the bridges in the
205efa246c0Sriastradh  * encoder chain, starting from the first bridge to the last.
206efa246c0Sriastradh  *
207efa246c0Sriastradh  * Note: the bridge passed should be the one closest to the encoder
208efa246c0Sriastradh  *
209efa246c0Sriastradh  * RETURNS:
210efa246c0Sriastradh  * true on success, false on failure
211efa246c0Sriastradh  */
drm_bridge_chain_mode_fixup(struct drm_bridge * bridge,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)212*41ec0267Sriastradh bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge,
213efa246c0Sriastradh 				 const struct drm_display_mode *mode,
214efa246c0Sriastradh 				 struct drm_display_mode *adjusted_mode)
215efa246c0Sriastradh {
216*41ec0267Sriastradh 	struct drm_encoder *encoder;
217efa246c0Sriastradh 
218efa246c0Sriastradh 	if (!bridge)
219efa246c0Sriastradh 		return true;
220efa246c0Sriastradh 
221*41ec0267Sriastradh 	encoder = bridge->encoder;
222*41ec0267Sriastradh 	list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
223*41ec0267Sriastradh 		if (!bridge->funcs->mode_fixup)
224*41ec0267Sriastradh 			continue;
225efa246c0Sriastradh 
226*41ec0267Sriastradh 		if (!bridge->funcs->mode_fixup(bridge, mode, adjusted_mode))
227*41ec0267Sriastradh 			return false;
228efa246c0Sriastradh 	}
229*41ec0267Sriastradh 
230*41ec0267Sriastradh 	return true;
231*41ec0267Sriastradh }
232*41ec0267Sriastradh EXPORT_SYMBOL(drm_bridge_chain_mode_fixup);
233efa246c0Sriastradh 
234efa246c0Sriastradh /**
235*41ec0267Sriastradh  * drm_bridge_chain_mode_valid - validate the mode against all bridges in the
236*41ec0267Sriastradh  *				 encoder chain.
237*41ec0267Sriastradh  * @bridge: bridge control structure
238*41ec0267Sriastradh  * @mode: desired mode to be validated
239*41ec0267Sriastradh  *
240*41ec0267Sriastradh  * Calls &drm_bridge_funcs.mode_valid for all the bridges in the encoder
241*41ec0267Sriastradh  * chain, starting from the first bridge to the last. If at least one bridge
242*41ec0267Sriastradh  * does not accept the mode the function returns the error code.
243*41ec0267Sriastradh  *
244*41ec0267Sriastradh  * Note: the bridge passed should be the one closest to the encoder.
245*41ec0267Sriastradh  *
246*41ec0267Sriastradh  * RETURNS:
247*41ec0267Sriastradh  * MODE_OK on success, drm_mode_status Enum error code on failure
248*41ec0267Sriastradh  */
249*41ec0267Sriastradh enum drm_mode_status
drm_bridge_chain_mode_valid(struct drm_bridge * bridge,const struct drm_display_mode * mode)250*41ec0267Sriastradh drm_bridge_chain_mode_valid(struct drm_bridge *bridge,
251*41ec0267Sriastradh 			    const struct drm_display_mode *mode)
252*41ec0267Sriastradh {
253*41ec0267Sriastradh 	struct drm_encoder *encoder;
254*41ec0267Sriastradh 
255*41ec0267Sriastradh 	if (!bridge)
256*41ec0267Sriastradh 		return MODE_OK;
257*41ec0267Sriastradh 
258*41ec0267Sriastradh 	encoder = bridge->encoder;
259*41ec0267Sriastradh 	list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
260*41ec0267Sriastradh 		enum drm_mode_status ret;
261*41ec0267Sriastradh 
262*41ec0267Sriastradh 		if (!bridge->funcs->mode_valid)
263*41ec0267Sriastradh 			continue;
264*41ec0267Sriastradh 
265*41ec0267Sriastradh 		ret = bridge->funcs->mode_valid(bridge, mode);
266*41ec0267Sriastradh 		if (ret != MODE_OK)
267*41ec0267Sriastradh 			return ret;
268*41ec0267Sriastradh 	}
269*41ec0267Sriastradh 
270*41ec0267Sriastradh 	return MODE_OK;
271*41ec0267Sriastradh }
272*41ec0267Sriastradh EXPORT_SYMBOL(drm_bridge_chain_mode_valid);
273*41ec0267Sriastradh 
274*41ec0267Sriastradh /**
275*41ec0267Sriastradh  * drm_bridge_chain_disable - disables all bridges in the encoder chain
276efa246c0Sriastradh  * @bridge: bridge control structure
277efa246c0Sriastradh  *
278*41ec0267Sriastradh  * Calls &drm_bridge_funcs.disable op for all the bridges in the encoder
279efa246c0Sriastradh  * chain, starting from the last bridge to the first. These are called before
280efa246c0Sriastradh  * calling the encoder's prepare op.
281efa246c0Sriastradh  *
282efa246c0Sriastradh  * Note: the bridge passed should be the one closest to the encoder
283efa246c0Sriastradh  */
drm_bridge_chain_disable(struct drm_bridge * bridge)284*41ec0267Sriastradh void drm_bridge_chain_disable(struct drm_bridge *bridge)
285efa246c0Sriastradh {
286*41ec0267Sriastradh 	struct drm_encoder *encoder;
287*41ec0267Sriastradh 	struct drm_bridge *iter;
288*41ec0267Sriastradh 
289efa246c0Sriastradh 	if (!bridge)
290efa246c0Sriastradh 		return;
291efa246c0Sriastradh 
292*41ec0267Sriastradh 	encoder = bridge->encoder;
293*41ec0267Sriastradh 	list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
294*41ec0267Sriastradh 		if (iter->funcs->disable)
295*41ec0267Sriastradh 			iter->funcs->disable(iter);
296efa246c0Sriastradh 
297*41ec0267Sriastradh 		if (iter == bridge)
298*41ec0267Sriastradh 			break;
299efa246c0Sriastradh 	}
300*41ec0267Sriastradh }
301*41ec0267Sriastradh EXPORT_SYMBOL(drm_bridge_chain_disable);
302efa246c0Sriastradh 
303efa246c0Sriastradh /**
304*41ec0267Sriastradh  * drm_bridge_chain_post_disable - cleans up after disabling all bridges in the
305*41ec0267Sriastradh  *				   encoder chain
306efa246c0Sriastradh  * @bridge: bridge control structure
307efa246c0Sriastradh  *
308*41ec0267Sriastradh  * Calls &drm_bridge_funcs.post_disable op for all the bridges in the
309efa246c0Sriastradh  * encoder chain, starting from the first bridge to the last. These are called
310efa246c0Sriastradh  * after completing the encoder's prepare op.
311efa246c0Sriastradh  *
312efa246c0Sriastradh  * Note: the bridge passed should be the one closest to the encoder
313efa246c0Sriastradh  */
drm_bridge_chain_post_disable(struct drm_bridge * bridge)314*41ec0267Sriastradh void drm_bridge_chain_post_disable(struct drm_bridge *bridge)
315efa246c0Sriastradh {
316*41ec0267Sriastradh 	struct drm_encoder *encoder;
317*41ec0267Sriastradh 
318efa246c0Sriastradh 	if (!bridge)
319efa246c0Sriastradh 		return;
320efa246c0Sriastradh 
321*41ec0267Sriastradh 	encoder = bridge->encoder;
322*41ec0267Sriastradh 	list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
323*41ec0267Sriastradh 		if (bridge->funcs->post_disable)
324efa246c0Sriastradh 			bridge->funcs->post_disable(bridge);
325efa246c0Sriastradh 	}
326*41ec0267Sriastradh }
327*41ec0267Sriastradh EXPORT_SYMBOL(drm_bridge_chain_post_disable);
328efa246c0Sriastradh 
329efa246c0Sriastradh /**
330*41ec0267Sriastradh  * drm_bridge_chain_mode_set - set proposed mode for all bridges in the
331efa246c0Sriastradh  *			       encoder chain
332efa246c0Sriastradh  * @bridge: bridge control structure
333*41ec0267Sriastradh  * @mode: desired mode to be set for the encoder chain
334*41ec0267Sriastradh  * @adjusted_mode: updated mode that works for this encoder chain
335efa246c0Sriastradh  *
336*41ec0267Sriastradh  * Calls &drm_bridge_funcs.mode_set op for all the bridges in the
337efa246c0Sriastradh  * encoder chain, starting from the first bridge to the last.
338efa246c0Sriastradh  *
339efa246c0Sriastradh  * Note: the bridge passed should be the one closest to the encoder
340efa246c0Sriastradh  */
drm_bridge_chain_mode_set(struct drm_bridge * bridge,const struct drm_display_mode * mode,const struct drm_display_mode * adjusted_mode)341*41ec0267Sriastradh void drm_bridge_chain_mode_set(struct drm_bridge *bridge,
342*41ec0267Sriastradh 			       const struct drm_display_mode *mode,
343*41ec0267Sriastradh 			       const struct drm_display_mode *adjusted_mode)
344efa246c0Sriastradh {
345*41ec0267Sriastradh 	struct drm_encoder *encoder;
346*41ec0267Sriastradh 
347efa246c0Sriastradh 	if (!bridge)
348efa246c0Sriastradh 		return;
349efa246c0Sriastradh 
350*41ec0267Sriastradh 	encoder = bridge->encoder;
351*41ec0267Sriastradh 	list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
352efa246c0Sriastradh 		if (bridge->funcs->mode_set)
353efa246c0Sriastradh 			bridge->funcs->mode_set(bridge, mode, adjusted_mode);
354efa246c0Sriastradh 	}
355*41ec0267Sriastradh }
356*41ec0267Sriastradh EXPORT_SYMBOL(drm_bridge_chain_mode_set);
357efa246c0Sriastradh 
358efa246c0Sriastradh /**
359*41ec0267Sriastradh  * drm_bridge_chain_pre_enable - prepares for enabling all bridges in the
360*41ec0267Sriastradh  *				 encoder chain
361efa246c0Sriastradh  * @bridge: bridge control structure
362efa246c0Sriastradh  *
363*41ec0267Sriastradh  * Calls &drm_bridge_funcs.pre_enable op for all the bridges in the encoder
364efa246c0Sriastradh  * chain, starting from the last bridge to the first. These are called
365efa246c0Sriastradh  * before calling the encoder's commit op.
366efa246c0Sriastradh  *
367efa246c0Sriastradh  * Note: the bridge passed should be the one closest to the encoder
368efa246c0Sriastradh  */
drm_bridge_chain_pre_enable(struct drm_bridge * bridge)369*41ec0267Sriastradh void drm_bridge_chain_pre_enable(struct drm_bridge *bridge)
370efa246c0Sriastradh {
371*41ec0267Sriastradh 	struct drm_encoder *encoder;
372*41ec0267Sriastradh 	struct drm_bridge *iter;
373*41ec0267Sriastradh 
374efa246c0Sriastradh 	if (!bridge)
375efa246c0Sriastradh 		return;
376efa246c0Sriastradh 
377*41ec0267Sriastradh 	encoder = bridge->encoder;
378*41ec0267Sriastradh 	list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
379*41ec0267Sriastradh 		if (iter->funcs->pre_enable)
380*41ec0267Sriastradh 			iter->funcs->pre_enable(iter);
381efa246c0Sriastradh 	}
382*41ec0267Sriastradh }
383*41ec0267Sriastradh EXPORT_SYMBOL(drm_bridge_chain_pre_enable);
384efa246c0Sriastradh 
385efa246c0Sriastradh /**
386*41ec0267Sriastradh  * drm_bridge_chain_enable - enables all bridges in the encoder chain
387efa246c0Sriastradh  * @bridge: bridge control structure
388efa246c0Sriastradh  *
389*41ec0267Sriastradh  * Calls &drm_bridge_funcs.enable op for all the bridges in the encoder
390efa246c0Sriastradh  * chain, starting from the first bridge to the last. These are called
391efa246c0Sriastradh  * after completing the encoder's commit op.
392efa246c0Sriastradh  *
393efa246c0Sriastradh  * Note that the bridge passed should be the one closest to the encoder
394efa246c0Sriastradh  */
drm_bridge_chain_enable(struct drm_bridge * bridge)395*41ec0267Sriastradh void drm_bridge_chain_enable(struct drm_bridge *bridge)
396efa246c0Sriastradh {
397*41ec0267Sriastradh 	struct drm_encoder *encoder;
398*41ec0267Sriastradh 
399efa246c0Sriastradh 	if (!bridge)
400efa246c0Sriastradh 		return;
401efa246c0Sriastradh 
402*41ec0267Sriastradh 	encoder = bridge->encoder;
403*41ec0267Sriastradh 	list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
404*41ec0267Sriastradh 		if (bridge->funcs->enable)
405efa246c0Sriastradh 			bridge->funcs->enable(bridge);
406efa246c0Sriastradh 	}
407*41ec0267Sriastradh }
408*41ec0267Sriastradh EXPORT_SYMBOL(drm_bridge_chain_enable);
409*41ec0267Sriastradh 
410*41ec0267Sriastradh /**
411*41ec0267Sriastradh  * drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain
412*41ec0267Sriastradh  * @bridge: bridge control structure
413*41ec0267Sriastradh  * @old_state: old atomic state
414*41ec0267Sriastradh  *
415*41ec0267Sriastradh  * Calls &drm_bridge_funcs.atomic_disable (falls back on
416*41ec0267Sriastradh  * &drm_bridge_funcs.disable) op for all the bridges in the encoder chain,
417*41ec0267Sriastradh  * starting from the last bridge to the first. These are called before calling
418*41ec0267Sriastradh  * &drm_encoder_helper_funcs.atomic_disable
419*41ec0267Sriastradh  *
420*41ec0267Sriastradh  * Note: the bridge passed should be the one closest to the encoder
421*41ec0267Sriastradh  */
drm_atomic_bridge_chain_disable(struct drm_bridge * bridge,struct drm_atomic_state * old_state)422*41ec0267Sriastradh void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
423*41ec0267Sriastradh 				     struct drm_atomic_state *old_state)
424*41ec0267Sriastradh {
425*41ec0267Sriastradh 	struct drm_encoder *encoder;
426*41ec0267Sriastradh 	struct drm_bridge *iter;
427*41ec0267Sriastradh 
428*41ec0267Sriastradh 	if (!bridge)
429*41ec0267Sriastradh 		return;
430*41ec0267Sriastradh 
431*41ec0267Sriastradh 	encoder = bridge->encoder;
432*41ec0267Sriastradh 	list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
433*41ec0267Sriastradh 		if (iter->funcs->atomic_disable)
434*41ec0267Sriastradh 			iter->funcs->atomic_disable(iter, old_state);
435*41ec0267Sriastradh 		else if (iter->funcs->disable)
436*41ec0267Sriastradh 			iter->funcs->disable(iter);
437*41ec0267Sriastradh 
438*41ec0267Sriastradh 		if (iter == bridge)
439*41ec0267Sriastradh 			break;
440*41ec0267Sriastradh 	}
441*41ec0267Sriastradh }
442*41ec0267Sriastradh EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
443*41ec0267Sriastradh 
444*41ec0267Sriastradh /**
445*41ec0267Sriastradh  * drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges
446*41ec0267Sriastradh  *					  in the encoder chain
447*41ec0267Sriastradh  * @bridge: bridge control structure
448*41ec0267Sriastradh  * @old_state: old atomic state
449*41ec0267Sriastradh  *
450*41ec0267Sriastradh  * Calls &drm_bridge_funcs.atomic_post_disable (falls back on
451*41ec0267Sriastradh  * &drm_bridge_funcs.post_disable) op for all the bridges in the encoder chain,
452*41ec0267Sriastradh  * starting from the first bridge to the last. These are called after completing
453*41ec0267Sriastradh  * &drm_encoder_helper_funcs.atomic_disable
454*41ec0267Sriastradh  *
455*41ec0267Sriastradh  * Note: the bridge passed should be the one closest to the encoder
456*41ec0267Sriastradh  */
drm_atomic_bridge_chain_post_disable(struct drm_bridge * bridge,struct drm_atomic_state * old_state)457*41ec0267Sriastradh void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
458*41ec0267Sriastradh 					  struct drm_atomic_state *old_state)
459*41ec0267Sriastradh {
460*41ec0267Sriastradh 	struct drm_encoder *encoder;
461*41ec0267Sriastradh 
462*41ec0267Sriastradh 	if (!bridge)
463*41ec0267Sriastradh 		return;
464*41ec0267Sriastradh 
465*41ec0267Sriastradh 	encoder = bridge->encoder;
466*41ec0267Sriastradh 	list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
467*41ec0267Sriastradh 		if (bridge->funcs->atomic_post_disable)
468*41ec0267Sriastradh 			bridge->funcs->atomic_post_disable(bridge, old_state);
469*41ec0267Sriastradh 		else if (bridge->funcs->post_disable)
470*41ec0267Sriastradh 			bridge->funcs->post_disable(bridge);
471*41ec0267Sriastradh 	}
472*41ec0267Sriastradh }
473*41ec0267Sriastradh EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
474*41ec0267Sriastradh 
475*41ec0267Sriastradh /**
476*41ec0267Sriastradh  * drm_atomic_bridge_chain_pre_enable - prepares for enabling all bridges in
477*41ec0267Sriastradh  *					the encoder chain
478*41ec0267Sriastradh  * @bridge: bridge control structure
479*41ec0267Sriastradh  * @old_state: old atomic state
480*41ec0267Sriastradh  *
481*41ec0267Sriastradh  * Calls &drm_bridge_funcs.atomic_pre_enable (falls back on
482*41ec0267Sriastradh  * &drm_bridge_funcs.pre_enable) op for all the bridges in the encoder chain,
483*41ec0267Sriastradh  * starting from the last bridge to the first. These are called before calling
484*41ec0267Sriastradh  * &drm_encoder_helper_funcs.atomic_enable
485*41ec0267Sriastradh  *
486*41ec0267Sriastradh  * Note: the bridge passed should be the one closest to the encoder
487*41ec0267Sriastradh  */
drm_atomic_bridge_chain_pre_enable(struct drm_bridge * bridge,struct drm_atomic_state * old_state)488*41ec0267Sriastradh void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
489*41ec0267Sriastradh 					struct drm_atomic_state *old_state)
490*41ec0267Sriastradh {
491*41ec0267Sriastradh 	struct drm_encoder *encoder;
492*41ec0267Sriastradh 	struct drm_bridge *iter;
493*41ec0267Sriastradh 
494*41ec0267Sriastradh 	if (!bridge)
495*41ec0267Sriastradh 		return;
496*41ec0267Sriastradh 
497*41ec0267Sriastradh 	encoder = bridge->encoder;
498*41ec0267Sriastradh 	list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
499*41ec0267Sriastradh 		if (iter->funcs->atomic_pre_enable)
500*41ec0267Sriastradh 			iter->funcs->atomic_pre_enable(iter, old_state);
501*41ec0267Sriastradh 		else if (iter->funcs->pre_enable)
502*41ec0267Sriastradh 			iter->funcs->pre_enable(iter);
503*41ec0267Sriastradh 
504*41ec0267Sriastradh 		if (iter == bridge)
505*41ec0267Sriastradh 			break;
506*41ec0267Sriastradh 	}
507*41ec0267Sriastradh }
508*41ec0267Sriastradh EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
509*41ec0267Sriastradh 
510*41ec0267Sriastradh /**
511*41ec0267Sriastradh  * drm_atomic_bridge_chain_enable - enables all bridges in the encoder chain
512*41ec0267Sriastradh  * @bridge: bridge control structure
513*41ec0267Sriastradh  * @old_state: old atomic state
514*41ec0267Sriastradh  *
515*41ec0267Sriastradh  * Calls &drm_bridge_funcs.atomic_enable (falls back on
516*41ec0267Sriastradh  * &drm_bridge_funcs.enable) op for all the bridges in the encoder chain,
517*41ec0267Sriastradh  * starting from the first bridge to the last. These are called after completing
518*41ec0267Sriastradh  * &drm_encoder_helper_funcs.atomic_enable
519*41ec0267Sriastradh  *
520*41ec0267Sriastradh  * Note: the bridge passed should be the one closest to the encoder
521*41ec0267Sriastradh  */
drm_atomic_bridge_chain_enable(struct drm_bridge * bridge,struct drm_atomic_state * old_state)522*41ec0267Sriastradh void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge,
523*41ec0267Sriastradh 				    struct drm_atomic_state *old_state)
524*41ec0267Sriastradh {
525*41ec0267Sriastradh 	struct drm_encoder *encoder;
526*41ec0267Sriastradh 
527*41ec0267Sriastradh 	if (!bridge)
528*41ec0267Sriastradh 		return;
529*41ec0267Sriastradh 
530*41ec0267Sriastradh 	encoder = bridge->encoder;
531*41ec0267Sriastradh 	list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
532*41ec0267Sriastradh 		if (bridge->funcs->atomic_enable)
533*41ec0267Sriastradh 			bridge->funcs->atomic_enable(bridge, old_state);
534*41ec0267Sriastradh 		else if (bridge->funcs->enable)
535*41ec0267Sriastradh 			bridge->funcs->enable(bridge);
536*41ec0267Sriastradh 	}
537*41ec0267Sriastradh }
538*41ec0267Sriastradh EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
539efa246c0Sriastradh 
540efa246c0Sriastradh #ifdef CONFIG_OF
541efa246c0Sriastradh /**
542efa246c0Sriastradh  * of_drm_find_bridge - find the bridge corresponding to the device node in
543efa246c0Sriastradh  *			the global bridge list
544efa246c0Sriastradh  *
545efa246c0Sriastradh  * @np: device node
546efa246c0Sriastradh  *
547efa246c0Sriastradh  * RETURNS:
548efa246c0Sriastradh  * drm_bridge control struct on success, NULL on failure
549efa246c0Sriastradh  */
of_drm_find_bridge(struct device_node * np)550efa246c0Sriastradh struct drm_bridge *of_drm_find_bridge(struct device_node *np)
551efa246c0Sriastradh {
552efa246c0Sriastradh 	struct drm_bridge *bridge;
553efa246c0Sriastradh 
554efa246c0Sriastradh 	mutex_lock(&bridge_lock);
555efa246c0Sriastradh 
556efa246c0Sriastradh 	list_for_each_entry(bridge, &bridge_list, list) {
557efa246c0Sriastradh 		if (bridge->of_node == np) {
558efa246c0Sriastradh 			mutex_unlock(&bridge_lock);
559efa246c0Sriastradh 			return bridge;
560efa246c0Sriastradh 		}
561efa246c0Sriastradh 	}
562efa246c0Sriastradh 
563efa246c0Sriastradh 	mutex_unlock(&bridge_lock);
564efa246c0Sriastradh 	return NULL;
565efa246c0Sriastradh }
566efa246c0Sriastradh EXPORT_SYMBOL(of_drm_find_bridge);
567efa246c0Sriastradh #endif
568efa246c0Sriastradh 
569efa246c0Sriastradh MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>");
570efa246c0Sriastradh MODULE_DESCRIPTION("DRM bridge infrastructure");
571efa246c0Sriastradh MODULE_LICENSE("GPL and additional rights");
572