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