xref: /dflybsd-src/sys/dev/drm/drm_bridge.c (revision aee94f86171368465eaa15d649743f13cea3363a)
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>
2619c468b4SFrançois Tigeot 
2719c468b4SFrançois Tigeot 
2819c468b4SFrançois Tigeot #include "drm/drmP.h"
2919c468b4SFrançois Tigeot 
3019c468b4SFrançois Tigeot /**
3119c468b4SFrançois Tigeot  * DOC: overview
3219c468b4SFrançois Tigeot  *
33*aee94f86SFrançois Tigeot  * struct &drm_bridge represents a device that hangs on to an encoder. These are
34*aee94f86SFrançois Tigeot  * handy when a regular &drm_encoder entity isn't enough to represent the entire
3519c468b4SFrançois Tigeot  * encoder chain.
3619c468b4SFrançois Tigeot  *
37*aee94f86SFrançois Tigeot  * A bridge is always attached to a single &drm_encoder at a time, but can be
3819c468b4SFrançois Tigeot  * either connected to it directly, or through an intermediate bridge:
3919c468b4SFrançois Tigeot  *
4019c468b4SFrançois Tigeot  *     encoder ---> bridge B ---> bridge A
4119c468b4SFrançois Tigeot  *
4219c468b4SFrançois Tigeot  * Here, the output of the encoder feeds to bridge B, and that furthers feeds to
4319c468b4SFrançois Tigeot  * bridge A.
4419c468b4SFrançois Tigeot  *
4519c468b4SFrançois Tigeot  * The driver using the bridge is responsible to make the associations between
4619c468b4SFrançois Tigeot  * the encoder and bridges. Once these links are made, the bridges will
4719c468b4SFrançois Tigeot  * participate along with encoder functions to perform mode_set/enable/disable
48*aee94f86SFrançois Tigeot  * through the ops provided in &drm_bridge_funcs.
4919c468b4SFrançois Tigeot  *
5019c468b4SFrançois Tigeot  * drm_bridge, like drm_panel, aren't drm_mode_object entities like planes,
51*aee94f86SFrançois Tigeot  * CRTCs, encoders or connectors and hence are not visible to userspace. They
52*aee94f86SFrançois Tigeot  * just provide additional hooks to get the desired output at the end of the
53*aee94f86SFrançois Tigeot  * encoder chain.
54*aee94f86SFrançois Tigeot  *
55*aee94f86SFrançois Tigeot  * Bridges can also be chained up using the next pointer in struct &drm_bridge.
56*aee94f86SFrançois Tigeot  *
57*aee94f86SFrançois Tigeot  * Both legacy CRTC helpers and the new atomic modeset helpers support bridges.
5819c468b4SFrançois Tigeot  */
5919c468b4SFrançois Tigeot 
6019c468b4SFrançois Tigeot static DEFINE_MUTEX(bridge_lock);
6119c468b4SFrançois Tigeot static LINUX_LIST_HEAD(bridge_list);
6219c468b4SFrançois Tigeot 
6319c468b4SFrançois Tigeot /**
6419c468b4SFrançois Tigeot  * drm_bridge_add - add the given bridge to the global bridge list
6519c468b4SFrançois Tigeot  *
6619c468b4SFrançois Tigeot  * @bridge: bridge control structure
6719c468b4SFrançois Tigeot  *
6819c468b4SFrançois Tigeot  * RETURNS:
6919c468b4SFrançois Tigeot  * Unconditionally returns Zero.
7019c468b4SFrançois Tigeot  */
7119c468b4SFrançois Tigeot int 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 	return 0;
7819c468b4SFrançois Tigeot }
7919c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_add);
8019c468b4SFrançois Tigeot 
8119c468b4SFrançois Tigeot /**
8219c468b4SFrançois Tigeot  * drm_bridge_remove - remove the given bridge from the global bridge list
8319c468b4SFrançois Tigeot  *
8419c468b4SFrançois Tigeot  * @bridge: bridge control structure
8519c468b4SFrançois Tigeot  */
8619c468b4SFrançois Tigeot void drm_bridge_remove(struct drm_bridge *bridge)
8719c468b4SFrançois Tigeot {
8819c468b4SFrançois Tigeot 	mutex_lock(&bridge_lock);
8919c468b4SFrançois Tigeot 	list_del_init(&bridge->list);
9019c468b4SFrançois Tigeot 	mutex_unlock(&bridge_lock);
9119c468b4SFrançois Tigeot }
9219c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_remove);
9319c468b4SFrançois Tigeot 
9419c468b4SFrançois Tigeot /**
9519c468b4SFrançois Tigeot  * drm_bridge_attach - associate given bridge to our DRM device
9619c468b4SFrançois Tigeot  *
9719c468b4SFrançois Tigeot  * @dev: DRM device
9819c468b4SFrançois Tigeot  * @bridge: bridge control structure
9919c468b4SFrançois Tigeot  *
10019c468b4SFrançois Tigeot  * called by a kms driver to link one of our encoder/bridge to the given
10119c468b4SFrançois Tigeot  * bridge.
10219c468b4SFrançois Tigeot  *
10319c468b4SFrançois Tigeot  * Note that setting up links between the bridge and our encoder/bridge
10419c468b4SFrançois Tigeot  * objects needs to be handled by the kms driver itself
10519c468b4SFrançois Tigeot  *
10619c468b4SFrançois Tigeot  * RETURNS:
10719c468b4SFrançois Tigeot  * Zero on success, error code on failure
10819c468b4SFrançois Tigeot  */
10919c468b4SFrançois Tigeot int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
11019c468b4SFrançois Tigeot {
11119c468b4SFrançois Tigeot 	if (!dev || !bridge)
11219c468b4SFrançois Tigeot 		return -EINVAL;
11319c468b4SFrançois Tigeot 
11419c468b4SFrançois Tigeot 	if (bridge->dev)
11519c468b4SFrançois Tigeot 		return -EBUSY;
11619c468b4SFrançois Tigeot 
11719c468b4SFrançois Tigeot 	bridge->dev = dev;
11819c468b4SFrançois Tigeot 
11919c468b4SFrançois Tigeot 	if (bridge->funcs->attach)
12019c468b4SFrançois Tigeot 		return bridge->funcs->attach(bridge);
12119c468b4SFrançois Tigeot 
12219c468b4SFrançois Tigeot 	return 0;
12319c468b4SFrançois Tigeot }
12419c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_attach);
12519c468b4SFrançois Tigeot 
12619c468b4SFrançois Tigeot /**
12719c468b4SFrançois Tigeot  * DOC: bridge callbacks
12819c468b4SFrançois Tigeot  *
129*aee94f86SFrançois Tigeot  * The &drm_bridge_funcs ops are populated by the bridge driver. The DRM
130*aee94f86SFrançois Tigeot  * internals (atomic and CRTC helpers) use the helpers defined in drm_bridge.c
131*aee94f86SFrançois Tigeot  * These helpers call a specific &drm_bridge_funcs op for all the bridges
13219c468b4SFrançois Tigeot  * during encoder configuration.
13319c468b4SFrançois Tigeot  *
134*aee94f86SFrançois Tigeot  * For detailed specification of the bridge callbacks see &drm_bridge_funcs.
13519c468b4SFrançois Tigeot  */
13619c468b4SFrançois Tigeot 
13719c468b4SFrançois Tigeot /**
13819c468b4SFrançois Tigeot  * drm_bridge_mode_fixup - fixup proposed mode for all bridges in the
13919c468b4SFrançois Tigeot  *			   encoder chain
14019c468b4SFrançois Tigeot  * @bridge: bridge control structure
14119c468b4SFrançois Tigeot  * @mode: desired mode to be set for the bridge
14219c468b4SFrançois Tigeot  * @adjusted_mode: updated mode that works for this bridge
14319c468b4SFrançois Tigeot  *
144*aee94f86SFrançois Tigeot  * Calls ->mode_fixup() &drm_bridge_funcs op for all the bridges in the
14519c468b4SFrançois Tigeot  * encoder chain, starting from the first bridge to the last.
14619c468b4SFrançois Tigeot  *
14719c468b4SFrançois Tigeot  * Note: the bridge passed should be the one closest to the encoder
14819c468b4SFrançois Tigeot  *
14919c468b4SFrançois Tigeot  * RETURNS:
15019c468b4SFrançois Tigeot  * true on success, false on failure
15119c468b4SFrançois Tigeot  */
15219c468b4SFrançois Tigeot bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
15319c468b4SFrançois Tigeot 			const struct drm_display_mode *mode,
15419c468b4SFrançois Tigeot 			struct drm_display_mode *adjusted_mode)
15519c468b4SFrançois Tigeot {
15619c468b4SFrançois Tigeot 	bool ret = true;
15719c468b4SFrançois Tigeot 
15819c468b4SFrançois Tigeot 	if (!bridge)
15919c468b4SFrançois Tigeot 		return true;
16019c468b4SFrançois Tigeot 
16119c468b4SFrançois Tigeot 	if (bridge->funcs->mode_fixup)
16219c468b4SFrançois Tigeot 		ret = bridge->funcs->mode_fixup(bridge, mode, adjusted_mode);
16319c468b4SFrançois Tigeot 
16419c468b4SFrançois Tigeot 	ret = ret && drm_bridge_mode_fixup(bridge->next, mode, adjusted_mode);
16519c468b4SFrançois Tigeot 
16619c468b4SFrançois Tigeot 	return ret;
16719c468b4SFrançois Tigeot }
16819c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_mode_fixup);
16919c468b4SFrançois Tigeot 
17019c468b4SFrançois Tigeot /**
171*aee94f86SFrançois Tigeot  * drm_bridge_disable - calls ->disable() &drm_bridge_funcs op for all
17219c468b4SFrançois Tigeot  *			bridges in the encoder chain.
17319c468b4SFrançois Tigeot  * @bridge: bridge control structure
17419c468b4SFrançois Tigeot  *
175*aee94f86SFrançois Tigeot  * Calls ->disable() &drm_bridge_funcs op for all the bridges in the encoder
17619c468b4SFrançois Tigeot  * chain, starting from the last bridge to the first. These are called before
17719c468b4SFrançois Tigeot  * calling the encoder's prepare op.
17819c468b4SFrançois Tigeot  *
17919c468b4SFrançois Tigeot  * Note: the bridge passed should be the one closest to the encoder
18019c468b4SFrançois Tigeot  */
18119c468b4SFrançois Tigeot void drm_bridge_disable(struct drm_bridge *bridge)
18219c468b4SFrançois Tigeot {
18319c468b4SFrançois Tigeot 	if (!bridge)
18419c468b4SFrançois Tigeot 		return;
18519c468b4SFrançois Tigeot 
18619c468b4SFrançois Tigeot 	drm_bridge_disable(bridge->next);
18719c468b4SFrançois Tigeot 
18819c468b4SFrançois Tigeot 	bridge->funcs->disable(bridge);
18919c468b4SFrançois Tigeot }
19019c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_disable);
19119c468b4SFrançois Tigeot 
19219c468b4SFrançois Tigeot /**
193*aee94f86SFrançois Tigeot  * drm_bridge_post_disable - calls ->post_disable() &drm_bridge_funcs op for
19419c468b4SFrançois Tigeot  *			     all bridges in the encoder chain.
19519c468b4SFrançois Tigeot  * @bridge: bridge control structure
19619c468b4SFrançois Tigeot  *
197*aee94f86SFrançois Tigeot  * Calls ->post_disable() &drm_bridge_funcs op for all the bridges in the
19819c468b4SFrançois Tigeot  * encoder chain, starting from the first bridge to the last. These are called
19919c468b4SFrançois Tigeot  * after completing the encoder's prepare op.
20019c468b4SFrançois Tigeot  *
20119c468b4SFrançois Tigeot  * Note: the bridge passed should be the one closest to the encoder
20219c468b4SFrançois Tigeot  */
20319c468b4SFrançois Tigeot void drm_bridge_post_disable(struct drm_bridge *bridge)
20419c468b4SFrançois Tigeot {
20519c468b4SFrançois Tigeot 	if (!bridge)
20619c468b4SFrançois Tigeot 		return;
20719c468b4SFrançois Tigeot 
20819c468b4SFrançois Tigeot 	bridge->funcs->post_disable(bridge);
20919c468b4SFrançois Tigeot 
21019c468b4SFrançois Tigeot 	drm_bridge_post_disable(bridge->next);
21119c468b4SFrançois Tigeot }
21219c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_post_disable);
21319c468b4SFrançois Tigeot 
21419c468b4SFrançois Tigeot /**
21519c468b4SFrançois Tigeot  * drm_bridge_mode_set - set proposed mode for all bridges in the
21619c468b4SFrançois Tigeot  *			 encoder chain
21719c468b4SFrançois Tigeot  * @bridge: bridge control structure
21819c468b4SFrançois Tigeot  * @mode: desired mode to be set for the bridge
21919c468b4SFrançois Tigeot  * @adjusted_mode: updated mode that works for this bridge
22019c468b4SFrançois Tigeot  *
221*aee94f86SFrançois Tigeot  * Calls ->mode_set() &drm_bridge_funcs op for all the bridges in the
22219c468b4SFrançois Tigeot  * encoder chain, starting from the first bridge to the last.
22319c468b4SFrançois Tigeot  *
22419c468b4SFrançois Tigeot  * Note: the bridge passed should be the one closest to the encoder
22519c468b4SFrançois Tigeot  */
22619c468b4SFrançois Tigeot void drm_bridge_mode_set(struct drm_bridge *bridge,
22719c468b4SFrançois Tigeot 			struct drm_display_mode *mode,
22819c468b4SFrançois Tigeot 			struct drm_display_mode *adjusted_mode)
22919c468b4SFrançois Tigeot {
23019c468b4SFrançois Tigeot 	if (!bridge)
23119c468b4SFrançois Tigeot 		return;
23219c468b4SFrançois Tigeot 
23319c468b4SFrançois Tigeot 	if (bridge->funcs->mode_set)
23419c468b4SFrançois Tigeot 		bridge->funcs->mode_set(bridge, mode, adjusted_mode);
23519c468b4SFrançois Tigeot 
23619c468b4SFrançois Tigeot 	drm_bridge_mode_set(bridge->next, mode, adjusted_mode);
23719c468b4SFrançois Tigeot }
23819c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_mode_set);
23919c468b4SFrançois Tigeot 
24019c468b4SFrançois Tigeot /**
241*aee94f86SFrançois Tigeot  * drm_bridge_pre_enable - calls ->pre_enable() &drm_bridge_funcs op for all
24219c468b4SFrançois Tigeot  *			   bridges in the encoder chain.
24319c468b4SFrançois Tigeot  * @bridge: bridge control structure
24419c468b4SFrançois Tigeot  *
245*aee94f86SFrançois Tigeot  * Calls ->pre_enable() &drm_bridge_funcs op for all the bridges in the encoder
24619c468b4SFrançois Tigeot  * chain, starting from the last bridge to the first. These are called
24719c468b4SFrançois Tigeot  * before calling the encoder's commit op.
24819c468b4SFrançois Tigeot  *
24919c468b4SFrançois Tigeot  * Note: the bridge passed should be the one closest to the encoder
25019c468b4SFrançois Tigeot  */
25119c468b4SFrançois Tigeot void drm_bridge_pre_enable(struct drm_bridge *bridge)
25219c468b4SFrançois Tigeot {
25319c468b4SFrançois Tigeot 	if (!bridge)
25419c468b4SFrançois Tigeot 		return;
25519c468b4SFrançois Tigeot 
25619c468b4SFrançois Tigeot 	drm_bridge_pre_enable(bridge->next);
25719c468b4SFrançois Tigeot 
25819c468b4SFrançois Tigeot 	bridge->funcs->pre_enable(bridge);
25919c468b4SFrançois Tigeot }
26019c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_pre_enable);
26119c468b4SFrançois Tigeot 
26219c468b4SFrançois Tigeot /**
263*aee94f86SFrançois Tigeot  * drm_bridge_enable - calls ->enable() &drm_bridge_funcs op for all bridges
26419c468b4SFrançois Tigeot  *		       in the encoder chain.
26519c468b4SFrançois Tigeot  * @bridge: bridge control structure
26619c468b4SFrançois Tigeot  *
267*aee94f86SFrançois Tigeot  * Calls ->enable() &drm_bridge_funcs op for all the bridges in the encoder
26819c468b4SFrançois Tigeot  * chain, starting from the first bridge to the last. These are called
26919c468b4SFrançois Tigeot  * after completing the encoder's commit op.
27019c468b4SFrançois Tigeot  *
27119c468b4SFrançois Tigeot  * Note that the bridge passed should be the one closest to the encoder
27219c468b4SFrançois Tigeot  */
27319c468b4SFrançois Tigeot void drm_bridge_enable(struct drm_bridge *bridge)
27419c468b4SFrançois Tigeot {
27519c468b4SFrançois Tigeot 	if (!bridge)
27619c468b4SFrançois Tigeot 		return;
27719c468b4SFrançois Tigeot 
27819c468b4SFrançois Tigeot 	bridge->funcs->enable(bridge);
27919c468b4SFrançois Tigeot 
28019c468b4SFrançois Tigeot 	drm_bridge_enable(bridge->next);
28119c468b4SFrançois Tigeot }
28219c468b4SFrançois Tigeot EXPORT_SYMBOL(drm_bridge_enable);
28319c468b4SFrançois Tigeot 
28419c468b4SFrançois Tigeot #ifdef CONFIG_OF
28519c468b4SFrançois Tigeot /**
28619c468b4SFrançois Tigeot  * of_drm_find_bridge - find the bridge corresponding to the device node in
28719c468b4SFrançois Tigeot  *			the global bridge list
28819c468b4SFrançois Tigeot  *
28919c468b4SFrançois Tigeot  * @np: device node
29019c468b4SFrançois Tigeot  *
29119c468b4SFrançois Tigeot  * RETURNS:
29219c468b4SFrançois Tigeot  * drm_bridge control struct on success, NULL on failure
29319c468b4SFrançois Tigeot  */
29419c468b4SFrançois Tigeot struct drm_bridge *of_drm_find_bridge(struct device_node *np)
29519c468b4SFrançois Tigeot {
29619c468b4SFrançois Tigeot 	struct drm_bridge *bridge;
29719c468b4SFrançois Tigeot 
29819c468b4SFrançois Tigeot 	mutex_lock(&bridge_lock);
29919c468b4SFrançois Tigeot 
30019c468b4SFrançois Tigeot 	list_for_each_entry(bridge, &bridge_list, list) {
30119c468b4SFrançois Tigeot 		if (bridge->of_node == np) {
30219c468b4SFrançois Tigeot 			mutex_unlock(&bridge_lock);
30319c468b4SFrançois Tigeot 			return bridge;
30419c468b4SFrançois Tigeot 		}
30519c468b4SFrançois Tigeot 	}
30619c468b4SFrançois Tigeot 
30719c468b4SFrançois Tigeot 	mutex_unlock(&bridge_lock);
30819c468b4SFrançois Tigeot 	return NULL;
30919c468b4SFrançois Tigeot }
31019c468b4SFrançois Tigeot EXPORT_SYMBOL(of_drm_find_bridge);
31119c468b4SFrançois Tigeot #endif
31219c468b4SFrançois Tigeot 
31319c468b4SFrançois Tigeot MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>");
31419c468b4SFrançois Tigeot MODULE_DESCRIPTION("DRM bridge infrastructure");
315