13d3f8b1fSAjay Kumar /*
23d3f8b1fSAjay Kumar * Copyright (c) 2014 Samsung Electronics Co., Ltd
33d3f8b1fSAjay Kumar *
43d3f8b1fSAjay Kumar * Permission is hereby granted, free of charge, to any person obtaining a
53d3f8b1fSAjay Kumar * copy of this software and associated documentation files (the "Software"),
63d3f8b1fSAjay Kumar * to deal in the Software without restriction, including without limitation
73d3f8b1fSAjay Kumar * the rights to use, copy, modify, merge, publish, distribute, sub license,
83d3f8b1fSAjay Kumar * and/or sell copies of the Software, and to permit persons to whom the
93d3f8b1fSAjay Kumar * Software is furnished to do so, subject to the following conditions:
103d3f8b1fSAjay Kumar *
113d3f8b1fSAjay Kumar * The above copyright notice and this permission notice (including the
123d3f8b1fSAjay Kumar * next paragraph) shall be included in all copies or substantial portions
133d3f8b1fSAjay Kumar * of the Software.
143d3f8b1fSAjay Kumar *
153d3f8b1fSAjay Kumar * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
163d3f8b1fSAjay Kumar * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
173d3f8b1fSAjay Kumar * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
183d3f8b1fSAjay Kumar * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
193d3f8b1fSAjay Kumar * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
203d3f8b1fSAjay Kumar * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
213d3f8b1fSAjay Kumar * DEALINGS IN THE SOFTWARE.
223d3f8b1fSAjay Kumar */
233d3f8b1fSAjay Kumar
243d3f8b1fSAjay Kumar #include <linux/err.h>
2572bd9ea3SVille Syrjälä #include <linux/media-bus-format.h>
263d3f8b1fSAjay Kumar #include <linux/module.h>
27199e4e96SDaniel Vetter #include <linux/mutex.h>
283d3f8b1fSAjay Kumar
2975146591SBoris Brezillon #include <drm/drm_atomic_state_helper.h>
30199e4e96SDaniel Vetter #include <drm/drm_bridge.h>
312b6aaf7bSJani Nikula #include <drm/drm_debugfs.h>
322b6aaf7bSJani Nikula #include <drm/drm_edid.h>
333bb80f24SLaurent Pinchart #include <drm/drm_encoder.h>
348e4bb53cSTomi Valkeinen #include <drm/drm_file.h>
3587ea9580SMaxime Ripard #include <drm/drm_of.h>
36fb8d617fSLaurent Pinchart #include <drm/drm_print.h>
373d3f8b1fSAjay Kumar
384a878c03SLaurent Pinchart #include "drm_crtc_internal.h"
394a878c03SLaurent Pinchart
402331b4e4SArchit Taneja /**
412331b4e4SArchit Taneja * DOC: overview
422331b4e4SArchit Taneja *
43ea0dd85aSDaniel Vetter * &struct drm_bridge represents a device that hangs on to an encoder. These are
44da024fe5SDaniel Vetter * handy when a regular &drm_encoder entity isn't enough to represent the entire
452331b4e4SArchit Taneja * encoder chain.
462331b4e4SArchit Taneja *
47da024fe5SDaniel Vetter * A bridge is always attached to a single &drm_encoder at a time, but can be
480451369bSLaurent Pinchart * either connected to it directly, or through a chain of bridges::
492331b4e4SArchit Taneja *
500451369bSLaurent Pinchart * [ CRTC ---> ] Encoder ---> Bridge A ---> Bridge B
512331b4e4SArchit Taneja *
520451369bSLaurent Pinchart * Here, the output of the encoder feeds to bridge A, and that furthers feeds to
530451369bSLaurent Pinchart * bridge B. Bridge chains can be arbitrarily long, and shall be fully linear:
540451369bSLaurent Pinchart * Chaining multiple bridges to the output of a bridge, or the same bridge to
550451369bSLaurent Pinchart * the output of different bridges, is not supported.
562331b4e4SArchit Taneja *
578886815fSMaxime Ripard * &drm_bridge, like &drm_panel, aren't &drm_mode_object entities like planes,
588886815fSMaxime Ripard * CRTCs, encoders or connectors and hence are not visible to userspace. They
598886815fSMaxime Ripard * just provide additional hooks to get the desired output at the end of the
608886815fSMaxime Ripard * encoder chain.
618886815fSMaxime Ripard */
628886815fSMaxime Ripard
638886815fSMaxime Ripard /**
648886815fSMaxime Ripard * DOC: display driver integration
658886815fSMaxime Ripard *
660451369bSLaurent Pinchart * Display drivers are responsible for linking encoders with the first bridge
670451369bSLaurent Pinchart * in the chains. This is done by acquiring the appropriate bridge with
6887ea9580SMaxime Ripard * devm_drm_of_get_bridge(). Once acquired, the bridge shall be attached to the
6987ea9580SMaxime Ripard * encoder with a call to drm_bridge_attach().
702331b4e4SArchit Taneja *
710451369bSLaurent Pinchart * Bridges are responsible for linking themselves with the next bridge in the
720451369bSLaurent Pinchart * chain, if any. This is done the same way as for encoders, with the call to
730451369bSLaurent Pinchart * drm_bridge_attach() occurring in the &drm_bridge_funcs.attach operation.
740451369bSLaurent Pinchart *
750451369bSLaurent Pinchart * Once these links are created, the bridges can participate along with encoder
760451369bSLaurent Pinchart * functions to perform mode validation and fixup (through
770451369bSLaurent Pinchart * drm_bridge_chain_mode_valid() and drm_atomic_bridge_chain_check()), mode
780451369bSLaurent Pinchart * setting (through drm_bridge_chain_mode_set()), enable (through
790451369bSLaurent Pinchart * drm_atomic_bridge_chain_pre_enable() and drm_atomic_bridge_chain_enable())
800451369bSLaurent Pinchart * and disable (through drm_atomic_bridge_chain_disable() and
810451369bSLaurent Pinchart * drm_atomic_bridge_chain_post_disable()). Those functions call the
820451369bSLaurent Pinchart * corresponding operations provided in &drm_bridge_funcs in sequence for all
830451369bSLaurent Pinchart * bridges in the chain.
840451369bSLaurent Pinchart *
850451369bSLaurent Pinchart * For display drivers that use the atomic helpers
860451369bSLaurent Pinchart * drm_atomic_helper_check_modeset(),
870451369bSLaurent Pinchart * drm_atomic_helper_commit_modeset_enables() and
880451369bSLaurent Pinchart * drm_atomic_helper_commit_modeset_disables() (either directly in hand-rolled
890451369bSLaurent Pinchart * commit check and commit tail handlers, or through the higher-level
900451369bSLaurent Pinchart * drm_atomic_helper_check() and drm_atomic_helper_commit_tail() or
910451369bSLaurent Pinchart * drm_atomic_helper_commit_tail_rpm() helpers), this is done transparently and
920451369bSLaurent Pinchart * requires no intervention from the driver. For other drivers, the relevant
930451369bSLaurent Pinchart * DRM bridge chain functions shall be called manually.
940451369bSLaurent Pinchart *
955e20bdf3SLaurent Pinchart * Bridges also participate in implementing the &drm_connector at the end of
965e20bdf3SLaurent Pinchart * the bridge chain. Display drivers may use the drm_bridge_connector_init()
975e20bdf3SLaurent Pinchart * helper to create the &drm_connector, or implement it manually on top of the
985e20bdf3SLaurent Pinchart * connector-related operations exposed by the bridge (see the overview
995e20bdf3SLaurent Pinchart * documentation of bridge operations for more details).
1002331b4e4SArchit Taneja */
1012331b4e4SArchit Taneja
102209264a8SMaxime Ripard /**
103209264a8SMaxime Ripard * DOC: special care dsi
104209264a8SMaxime Ripard *
105209264a8SMaxime Ripard * The interaction between the bridges and other frameworks involved in
106209264a8SMaxime Ripard * the probing of the upstream driver and the bridge driver can be
107209264a8SMaxime Ripard * challenging. Indeed, there's multiple cases that needs to be
108209264a8SMaxime Ripard * considered:
109209264a8SMaxime Ripard *
110209264a8SMaxime Ripard * - The upstream driver doesn't use the component framework and isn't a
111209264a8SMaxime Ripard * MIPI-DSI host. In this case, the bridge driver will probe at some
112209264a8SMaxime Ripard * point and the upstream driver should try to probe again by returning
113209264a8SMaxime Ripard * EPROBE_DEFER as long as the bridge driver hasn't probed.
114209264a8SMaxime Ripard *
115209264a8SMaxime Ripard * - The upstream driver doesn't use the component framework, but is a
116209264a8SMaxime Ripard * MIPI-DSI host. The bridge device uses the MIPI-DCS commands to be
117209264a8SMaxime Ripard * controlled. In this case, the bridge device is a child of the
118209264a8SMaxime Ripard * display device and when it will probe it's assured that the display
119209264a8SMaxime Ripard * device (and MIPI-DSI host) is present. The upstream driver will be
120209264a8SMaxime Ripard * assured that the bridge driver is connected between the
121209264a8SMaxime Ripard * &mipi_dsi_host_ops.attach and &mipi_dsi_host_ops.detach operations.
122209264a8SMaxime Ripard * Therefore, it must run mipi_dsi_host_register() in its probe
123209264a8SMaxime Ripard * function, and then run drm_bridge_attach() in its
124209264a8SMaxime Ripard * &mipi_dsi_host_ops.attach hook.
125209264a8SMaxime Ripard *
126209264a8SMaxime Ripard * - The upstream driver uses the component framework and is a MIPI-DSI
127209264a8SMaxime Ripard * host. The bridge device uses the MIPI-DCS commands to be
128209264a8SMaxime Ripard * controlled. This is the same situation than above, and can run
129209264a8SMaxime Ripard * mipi_dsi_host_register() in either its probe or bind hooks.
130209264a8SMaxime Ripard *
131209264a8SMaxime Ripard * - The upstream driver uses the component framework and is a MIPI-DSI
132209264a8SMaxime Ripard * host. The bridge device uses a separate bus (such as I2C) to be
133209264a8SMaxime Ripard * controlled. In this case, there's no correlation between the probe
134209264a8SMaxime Ripard * of the bridge and upstream drivers, so care must be taken to avoid
135209264a8SMaxime Ripard * an endless EPROBE_DEFER loop, with each driver waiting for the
136209264a8SMaxime Ripard * other to probe.
137209264a8SMaxime Ripard *
138209264a8SMaxime Ripard * The ideal pattern to cover the last item (and all the others in the
139209264a8SMaxime Ripard * MIPI-DSI host driver case) is to split the operations like this:
140209264a8SMaxime Ripard *
141209264a8SMaxime Ripard * - The MIPI-DSI host driver must run mipi_dsi_host_register() in its
142209264a8SMaxime Ripard * probe hook. It will make sure that the MIPI-DSI host sticks around,
143209264a8SMaxime Ripard * and that the driver's bind can be called.
144209264a8SMaxime Ripard *
145209264a8SMaxime Ripard * - In its probe hook, the bridge driver must try to find its MIPI-DSI
146209264a8SMaxime Ripard * host, register as a MIPI-DSI device and attach the MIPI-DSI device
147209264a8SMaxime Ripard * to its host. The bridge driver is now functional.
148209264a8SMaxime Ripard *
149209264a8SMaxime Ripard * - In its &struct mipi_dsi_host_ops.attach hook, the MIPI-DSI host can
150209264a8SMaxime Ripard * now add its component. Its bind hook will now be called and since
151209264a8SMaxime Ripard * the bridge driver is attached and registered, we can now look for
152209264a8SMaxime Ripard * and attach it.
153209264a8SMaxime Ripard *
154209264a8SMaxime Ripard * At this point, we're now certain that both the upstream driver and
155209264a8SMaxime Ripard * the bridge driver are functional and we can't have a deadlock-like
156209264a8SMaxime Ripard * situation when probing.
157209264a8SMaxime Ripard */
158209264a8SMaxime Ripard
159e373cdbeSDave Stevenson /**
160e373cdbeSDave Stevenson * DOC: dsi bridge operations
161e373cdbeSDave Stevenson *
162e373cdbeSDave Stevenson * DSI host interfaces are expected to be implemented as bridges rather than
163e373cdbeSDave Stevenson * encoders, however there are a few aspects of their operation that need to
164e373cdbeSDave Stevenson * be defined in order to provide a consistent interface.
165e373cdbeSDave Stevenson *
166e373cdbeSDave Stevenson * A DSI host should keep the PHY powered down until the pre_enable operation is
167e373cdbeSDave Stevenson * called. All lanes are in an undefined idle state up to this point, and it
168e373cdbeSDave Stevenson * must not be assumed that it is LP-11.
169e373cdbeSDave Stevenson * pre_enable should initialise the PHY, set the data lanes to LP-11, and the
170e373cdbeSDave Stevenson * clock lane to either LP-11 or HS depending on the mode_flag
171e373cdbeSDave Stevenson * %MIPI_DSI_CLOCK_NON_CONTINUOUS.
172e373cdbeSDave Stevenson *
173e373cdbeSDave Stevenson * Ordinarily the downstream bridge DSI peripheral pre_enable will have been
174e373cdbeSDave Stevenson * called before the DSI host. If the DSI peripheral requires LP-11 and/or
175e373cdbeSDave Stevenson * the clock lane to be in HS mode prior to pre_enable, then it can set the
176e373cdbeSDave Stevenson * &pre_enable_prev_first flag to request the pre_enable (and
177e373cdbeSDave Stevenson * post_disable) order to be altered to enable the DSI host first.
178e373cdbeSDave Stevenson *
179e373cdbeSDave Stevenson * Either the CRTC being enabled, or the DSI host enable operation should switch
180e373cdbeSDave Stevenson * the host to actively transmitting video on the data lanes.
181e373cdbeSDave Stevenson *
182e373cdbeSDave Stevenson * The reverse also applies. The DSI host disable operation or stopping the CRTC
183e373cdbeSDave Stevenson * should stop transmitting video, and the data lanes should return to the LP-11
184e373cdbeSDave Stevenson * state. The DSI host &post_disable operation should disable the PHY.
185e373cdbeSDave Stevenson * If the &pre_enable_prev_first flag is set, then the DSI peripheral's
186e373cdbeSDave Stevenson * bridge &post_disable will be called before the DSI host's post_disable.
187e373cdbeSDave Stevenson *
188e373cdbeSDave Stevenson * Whilst it is valid to call &host_transfer prior to pre_enable or after
189e373cdbeSDave Stevenson * post_disable, the exact state of the lanes is undefined at this point. The
190e373cdbeSDave Stevenson * DSI host should initialise the interface, transmit the data, and then disable
191e373cdbeSDave Stevenson * the interface again.
192e373cdbeSDave Stevenson *
193e373cdbeSDave Stevenson * Ultra Low Power State (ULPS) is not explicitly supported by DRM. If
194e373cdbeSDave Stevenson * implemented, it therefore needs to be handled entirely within the DSI Host
195e373cdbeSDave Stevenson * driver.
196e373cdbeSDave Stevenson */
197e373cdbeSDave Stevenson
1983d3f8b1fSAjay Kumar static DEFINE_MUTEX(bridge_lock);
1993d3f8b1fSAjay Kumar static LIST_HEAD(bridge_list);
2003d3f8b1fSAjay Kumar
2012331b4e4SArchit Taneja /**
2022331b4e4SArchit Taneja * drm_bridge_add - add the given bridge to the global bridge list
2032331b4e4SArchit Taneja *
2042331b4e4SArchit Taneja * @bridge: bridge control structure
2052331b4e4SArchit Taneja */
drm_bridge_add(struct drm_bridge * bridge)20699286884SInki Dae void drm_bridge_add(struct drm_bridge *bridge)
2073d3f8b1fSAjay Kumar {
20811f6c4b1SLaurent Pinchart mutex_init(&bridge->hpd_mutex);
20911f6c4b1SLaurent Pinchart
2103d3f8b1fSAjay Kumar mutex_lock(&bridge_lock);
2113d3f8b1fSAjay Kumar list_add_tail(&bridge->list, &bridge_list);
2123d3f8b1fSAjay Kumar mutex_unlock(&bridge_lock);
2133d3f8b1fSAjay Kumar }
2143d3f8b1fSAjay Kumar EXPORT_SYMBOL(drm_bridge_add);
2153d3f8b1fSAjay Kumar
drm_bridge_remove_void(void * bridge)21650e156bdSDouglas Anderson static void drm_bridge_remove_void(void *bridge)
21750e156bdSDouglas Anderson {
21850e156bdSDouglas Anderson drm_bridge_remove(bridge);
21950e156bdSDouglas Anderson }
22050e156bdSDouglas Anderson
22150e156bdSDouglas Anderson /**
22250e156bdSDouglas Anderson * devm_drm_bridge_add - devm managed version of drm_bridge_add()
22350e156bdSDouglas Anderson *
22450e156bdSDouglas Anderson * @dev: device to tie the bridge lifetime to
22550e156bdSDouglas Anderson * @bridge: bridge control structure
22650e156bdSDouglas Anderson *
22750e156bdSDouglas Anderson * This is the managed version of drm_bridge_add() which automatically
22850e156bdSDouglas Anderson * calls drm_bridge_remove() when @dev is unbound.
22950e156bdSDouglas Anderson *
23050e156bdSDouglas Anderson * Return: 0 if no error or negative error code.
23150e156bdSDouglas Anderson */
devm_drm_bridge_add(struct device * dev,struct drm_bridge * bridge)23250e156bdSDouglas Anderson int devm_drm_bridge_add(struct device *dev, struct drm_bridge *bridge)
23350e156bdSDouglas Anderson {
23450e156bdSDouglas Anderson drm_bridge_add(bridge);
23550e156bdSDouglas Anderson return devm_add_action_or_reset(dev, drm_bridge_remove_void, bridge);
23650e156bdSDouglas Anderson }
23750e156bdSDouglas Anderson EXPORT_SYMBOL(devm_drm_bridge_add);
23850e156bdSDouglas Anderson
2392331b4e4SArchit Taneja /**
2402331b4e4SArchit Taneja * drm_bridge_remove - remove the given bridge from the global bridge list
2412331b4e4SArchit Taneja *
2422331b4e4SArchit Taneja * @bridge: bridge control structure
2432331b4e4SArchit Taneja */
drm_bridge_remove(struct drm_bridge * bridge)2443d3f8b1fSAjay Kumar void drm_bridge_remove(struct drm_bridge *bridge)
2453d3f8b1fSAjay Kumar {
2463d3f8b1fSAjay Kumar mutex_lock(&bridge_lock);
2473d3f8b1fSAjay Kumar list_del_init(&bridge->list);
2483d3f8b1fSAjay Kumar mutex_unlock(&bridge_lock);
24911f6c4b1SLaurent Pinchart
25011f6c4b1SLaurent Pinchart mutex_destroy(&bridge->hpd_mutex);
2513d3f8b1fSAjay Kumar }
2523d3f8b1fSAjay Kumar EXPORT_SYMBOL(drm_bridge_remove);
2533d3f8b1fSAjay Kumar
25475146591SBoris Brezillon static struct drm_private_state *
drm_bridge_atomic_duplicate_priv_state(struct drm_private_obj * obj)25575146591SBoris Brezillon drm_bridge_atomic_duplicate_priv_state(struct drm_private_obj *obj)
25675146591SBoris Brezillon {
25775146591SBoris Brezillon struct drm_bridge *bridge = drm_priv_to_bridge(obj);
25875146591SBoris Brezillon struct drm_bridge_state *state;
25975146591SBoris Brezillon
26075146591SBoris Brezillon state = bridge->funcs->atomic_duplicate_state(bridge);
26175146591SBoris Brezillon return state ? &state->base : NULL;
26275146591SBoris Brezillon }
26375146591SBoris Brezillon
26475146591SBoris Brezillon static void
drm_bridge_atomic_destroy_priv_state(struct drm_private_obj * obj,struct drm_private_state * s)26575146591SBoris Brezillon drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj,
26675146591SBoris Brezillon struct drm_private_state *s)
26775146591SBoris Brezillon {
26875146591SBoris Brezillon struct drm_bridge_state *state = drm_priv_to_bridge_state(s);
26975146591SBoris Brezillon struct drm_bridge *bridge = drm_priv_to_bridge(obj);
27075146591SBoris Brezillon
27175146591SBoris Brezillon bridge->funcs->atomic_destroy_state(bridge, state);
27275146591SBoris Brezillon }
27375146591SBoris Brezillon
27475146591SBoris Brezillon static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
27575146591SBoris Brezillon .atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state,
27675146591SBoris Brezillon .atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
27775146591SBoris Brezillon };
27875146591SBoris Brezillon
2792331b4e4SArchit Taneja /**
2803bb80f24SLaurent Pinchart * drm_bridge_attach - attach the bridge to an encoder's chain
2812331b4e4SArchit Taneja *
2823bb80f24SLaurent Pinchart * @encoder: DRM encoder
2833bb80f24SLaurent Pinchart * @bridge: bridge to attach
2843bb80f24SLaurent Pinchart * @previous: previous bridge in the chain (optional)
285a25b988fSLaurent Pinchart * @flags: DRM_BRIDGE_ATTACH_* flags
2862331b4e4SArchit Taneja *
2873bb80f24SLaurent Pinchart * Called by a kms driver to link the bridge to an encoder's chain. The previous
2883bb80f24SLaurent Pinchart * argument specifies the previous bridge in the chain. If NULL, the bridge is
2893bb80f24SLaurent Pinchart * linked directly at the encoder's output. Otherwise it is linked at the
2903bb80f24SLaurent Pinchart * previous bridge's output.
2912331b4e4SArchit Taneja *
2923bb80f24SLaurent Pinchart * If non-NULL the previous bridge must be already attached by a call to this
2933bb80f24SLaurent Pinchart * function.
2942331b4e4SArchit Taneja *
295169cc4c7SPeter Rosin * Note that bridges attached to encoders are auto-detached during encoder
296169cc4c7SPeter Rosin * cleanup in drm_encoder_cleanup(), so drm_bridge_attach() should generally
297169cc4c7SPeter Rosin * *not* be balanced with a drm_bridge_detach() in driver code.
298169cc4c7SPeter Rosin *
2992331b4e4SArchit Taneja * RETURNS:
3002331b4e4SArchit Taneja * Zero on success, error code on failure
3012331b4e4SArchit Taneja */
drm_bridge_attach(struct drm_encoder * encoder,struct drm_bridge * bridge,struct drm_bridge * previous,enum drm_bridge_attach_flags flags)3023bb80f24SLaurent Pinchart int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
303a25b988fSLaurent Pinchart struct drm_bridge *previous,
304a25b988fSLaurent Pinchart enum drm_bridge_attach_flags flags)
3053d3f8b1fSAjay Kumar {
3063bb80f24SLaurent Pinchart int ret;
3073bb80f24SLaurent Pinchart
3083bb80f24SLaurent Pinchart if (!encoder || !bridge)
3093bb80f24SLaurent Pinchart return -EINVAL;
3103bb80f24SLaurent Pinchart
3113bb80f24SLaurent Pinchart if (previous && (!previous->dev || previous->encoder != encoder))
3123d3f8b1fSAjay Kumar return -EINVAL;
3133d3f8b1fSAjay Kumar
3143d3f8b1fSAjay Kumar if (bridge->dev)
3153d3f8b1fSAjay Kumar return -EBUSY;
3163d3f8b1fSAjay Kumar
3173bb80f24SLaurent Pinchart bridge->dev = encoder->dev;
3183bb80f24SLaurent Pinchart bridge->encoder = encoder;
3193d3f8b1fSAjay Kumar
32005193dc3SBoris Brezillon if (previous)
32105193dc3SBoris Brezillon list_add(&bridge->chain_node, &previous->chain_node);
32205193dc3SBoris Brezillon else
32305193dc3SBoris Brezillon list_add(&bridge->chain_node, &encoder->bridge_chain);
32405193dc3SBoris Brezillon
3253bb80f24SLaurent Pinchart if (bridge->funcs->attach) {
326a25b988fSLaurent Pinchart ret = bridge->funcs->attach(bridge, flags);
32775146591SBoris Brezillon if (ret < 0)
32875146591SBoris Brezillon goto err_reset_bridge;
3293d3f8b1fSAjay Kumar }
33075146591SBoris Brezillon
33175146591SBoris Brezillon if (bridge->funcs->atomic_reset) {
33275146591SBoris Brezillon struct drm_bridge_state *state;
33375146591SBoris Brezillon
33475146591SBoris Brezillon state = bridge->funcs->atomic_reset(bridge);
33575146591SBoris Brezillon if (IS_ERR(state)) {
33675146591SBoris Brezillon ret = PTR_ERR(state);
33775146591SBoris Brezillon goto err_detach_bridge;
33875146591SBoris Brezillon }
33975146591SBoris Brezillon
34075146591SBoris Brezillon drm_atomic_private_obj_init(bridge->dev, &bridge->base,
34175146591SBoris Brezillon &state->base,
34275146591SBoris Brezillon &drm_bridge_priv_state_funcs);
34309912635SBoris Brezillon }
34409912635SBoris Brezillon
34509912635SBoris Brezillon return 0;
34675146591SBoris Brezillon
34775146591SBoris Brezillon err_detach_bridge:
34875146591SBoris Brezillon if (bridge->funcs->detach)
34975146591SBoris Brezillon bridge->funcs->detach(bridge);
35075146591SBoris Brezillon
35175146591SBoris Brezillon err_reset_bridge:
35275146591SBoris Brezillon bridge->dev = NULL;
35375146591SBoris Brezillon bridge->encoder = NULL;
35475146591SBoris Brezillon list_del(&bridge->chain_node);
355fb8d617fSLaurent Pinchart
356fb8d617fSLaurent Pinchart #ifdef CONFIG_OF
357fb8d617fSLaurent Pinchart DRM_ERROR("failed to attach bridge %pOF to encoder %s: %d\n",
358fb8d617fSLaurent Pinchart bridge->of_node, encoder->name, ret);
359fb8d617fSLaurent Pinchart #else
360fb8d617fSLaurent Pinchart DRM_ERROR("failed to attach bridge to encoder %s: %d\n",
361fb8d617fSLaurent Pinchart encoder->name, ret);
362fb8d617fSLaurent Pinchart #endif
363fb8d617fSLaurent Pinchart
36475146591SBoris Brezillon return ret;
36509912635SBoris Brezillon }
3663d3f8b1fSAjay Kumar EXPORT_SYMBOL(drm_bridge_attach);
3673d3f8b1fSAjay Kumar
drm_bridge_detach(struct drm_bridge * bridge)368cf3bef95SAndrea Merello void drm_bridge_detach(struct drm_bridge *bridge)
369cf3bef95SAndrea Merello {
370cf3bef95SAndrea Merello if (WARN_ON(!bridge))
371cf3bef95SAndrea Merello return;
372cf3bef95SAndrea Merello
373cf3bef95SAndrea Merello if (WARN_ON(!bridge->dev))
374cf3bef95SAndrea Merello return;
375cf3bef95SAndrea Merello
37675146591SBoris Brezillon if (bridge->funcs->atomic_reset)
37775146591SBoris Brezillon drm_atomic_private_obj_fini(&bridge->base);
37875146591SBoris Brezillon
379cf3bef95SAndrea Merello if (bridge->funcs->detach)
380cf3bef95SAndrea Merello bridge->funcs->detach(bridge);
381cf3bef95SAndrea Merello
38205193dc3SBoris Brezillon list_del(&bridge->chain_node);
383cf3bef95SAndrea Merello bridge->dev = NULL;
384cf3bef95SAndrea Merello }
385cf3bef95SAndrea Merello
386cf3bef95SAndrea Merello /**
3870451369bSLaurent Pinchart * DOC: bridge operations
3882331b4e4SArchit Taneja *
3890451369bSLaurent Pinchart * Bridge drivers expose operations through the &drm_bridge_funcs structure.
3900451369bSLaurent Pinchart * The DRM internals (atomic and CRTC helpers) use the helpers defined in
3910451369bSLaurent Pinchart * drm_bridge.c to call bridge operations. Those operations are divided in
39211f6c4b1SLaurent Pinchart * three big categories to support different parts of the bridge usage.
3932331b4e4SArchit Taneja *
3940451369bSLaurent Pinchart * - The encoder-related operations support control of the bridges in the
3950451369bSLaurent Pinchart * chain, and are roughly counterparts to the &drm_encoder_helper_funcs
3960451369bSLaurent Pinchart * operations. They are used by the legacy CRTC and the atomic modeset
3970451369bSLaurent Pinchart * helpers to perform mode validation, fixup and setting, and enable and
3980451369bSLaurent Pinchart * disable the bridge automatically.
3990451369bSLaurent Pinchart *
4000451369bSLaurent Pinchart * The enable and disable operations are split in
4010451369bSLaurent Pinchart * &drm_bridge_funcs.pre_enable, &drm_bridge_funcs.enable,
4020451369bSLaurent Pinchart * &drm_bridge_funcs.disable and &drm_bridge_funcs.post_disable to provide
4030451369bSLaurent Pinchart * finer-grained control.
4040451369bSLaurent Pinchart *
4050451369bSLaurent Pinchart * Bridge drivers may implement the legacy version of those operations, or
4060451369bSLaurent Pinchart * the atomic version (prefixed with atomic\_), in which case they shall also
4070451369bSLaurent Pinchart * implement the atomic state bookkeeping operations
4080451369bSLaurent Pinchart * (&drm_bridge_funcs.atomic_duplicate_state,
4090451369bSLaurent Pinchart * &drm_bridge_funcs.atomic_destroy_state and &drm_bridge_funcs.reset).
4100451369bSLaurent Pinchart * Mixing atomic and non-atomic versions of the operations is not supported.
4110451369bSLaurent Pinchart *
4120451369bSLaurent Pinchart * - The bus format negotiation operations
4130451369bSLaurent Pinchart * &drm_bridge_funcs.atomic_get_output_bus_fmts and
4140451369bSLaurent Pinchart * &drm_bridge_funcs.atomic_get_input_bus_fmts allow bridge drivers to
4150451369bSLaurent Pinchart * negotiate the formats transmitted between bridges in the chain when
4160451369bSLaurent Pinchart * multiple formats are supported. Negotiation for formats is performed
4170451369bSLaurent Pinchart * transparently for display drivers by the atomic modeset helpers. Only
4180451369bSLaurent Pinchart * atomic versions of those operations exist, bridge drivers that need to
4190451369bSLaurent Pinchart * implement them shall thus also implement the atomic version of the
4200451369bSLaurent Pinchart * encoder-related operations. This feature is not supported by the legacy
4210451369bSLaurent Pinchart * CRTC helpers.
42211f6c4b1SLaurent Pinchart *
42311f6c4b1SLaurent Pinchart * - The connector-related operations support implementing a &drm_connector
42411f6c4b1SLaurent Pinchart * based on a chain of bridges. DRM bridges traditionally create a
42511f6c4b1SLaurent Pinchart * &drm_connector for bridges meant to be used at the end of the chain. This
42611f6c4b1SLaurent Pinchart * puts additional burden on bridge drivers, especially for bridges that may
42711f6c4b1SLaurent Pinchart * be used in the middle of a chain or at the end of it. Furthermore, it
42811f6c4b1SLaurent Pinchart * requires all operations of the &drm_connector to be handled by a single
42911f6c4b1SLaurent Pinchart * bridge, which doesn't always match the hardware architecture.
43011f6c4b1SLaurent Pinchart *
43111f6c4b1SLaurent Pinchart * To simplify bridge drivers and make the connector implementation more
43211f6c4b1SLaurent Pinchart * flexible, a new model allows bridges to unconditionally skip creation of
43311f6c4b1SLaurent Pinchart * &drm_connector and instead expose &drm_bridge_funcs operations to support
43411f6c4b1SLaurent Pinchart * an externally-implemented &drm_connector. Those operations are
43511f6c4b1SLaurent Pinchart * &drm_bridge_funcs.detect, &drm_bridge_funcs.get_modes,
43611f6c4b1SLaurent Pinchart * &drm_bridge_funcs.get_edid, &drm_bridge_funcs.hpd_notify,
43711f6c4b1SLaurent Pinchart * &drm_bridge_funcs.hpd_enable and &drm_bridge_funcs.hpd_disable. When
43811f6c4b1SLaurent Pinchart * implemented, display drivers shall create a &drm_connector instance for
43911f6c4b1SLaurent Pinchart * each chain of bridges, and implement those connector instances based on
44011f6c4b1SLaurent Pinchart * the bridge connector operations.
44111f6c4b1SLaurent Pinchart *
44211f6c4b1SLaurent Pinchart * Bridge drivers shall implement the connector-related operations for all
44311f6c4b1SLaurent Pinchart * the features that the bridge hardware support. For instance, if a bridge
44411f6c4b1SLaurent Pinchart * supports reading EDID, the &drm_bridge_funcs.get_edid shall be
44511f6c4b1SLaurent Pinchart * implemented. This however doesn't mean that the DDC lines are wired to the
44611f6c4b1SLaurent Pinchart * bridge on a particular platform, as they could also be connected to an I2C
44711f6c4b1SLaurent Pinchart * controller of the SoC. Support for the connector-related operations on the
44811f6c4b1SLaurent Pinchart * running platform is reported through the &drm_bridge.ops flags. Bridge
44911f6c4b1SLaurent Pinchart * drivers shall detect which operations they can support on the platform
45011f6c4b1SLaurent Pinchart * (usually this information is provided by ACPI or DT), and set the
45111f6c4b1SLaurent Pinchart * &drm_bridge.ops flags for all supported operations. A flag shall only be
45211f6c4b1SLaurent Pinchart * set if the corresponding &drm_bridge_funcs operation is implemented, but
45311f6c4b1SLaurent Pinchart * an implemented operation doesn't necessarily imply that the corresponding
45411f6c4b1SLaurent Pinchart * flag will be set. Display drivers shall use the &drm_bridge.ops flags to
45511f6c4b1SLaurent Pinchart * decide which bridge to delegate a connector operation to. This mechanism
45611f6c4b1SLaurent Pinchart * allows providing a single static const &drm_bridge_funcs instance in
45711f6c4b1SLaurent Pinchart * bridge drivers, improving security by storing function pointers in
45811f6c4b1SLaurent Pinchart * read-only memory.
459a25b988fSLaurent Pinchart *
460a25b988fSLaurent Pinchart * In order to ease transition, bridge drivers may support both the old and
461a25b988fSLaurent Pinchart * new models by making connector creation optional and implementing the
462a25b988fSLaurent Pinchart * connected-related bridge operations. Connector creation is then controlled
463a25b988fSLaurent Pinchart * by the flags argument to the drm_bridge_attach() function. Display drivers
464a25b988fSLaurent Pinchart * that support the new model and create connectors themselves shall set the
465a25b988fSLaurent Pinchart * %DRM_BRIDGE_ATTACH_NO_CONNECTOR flag, and bridge drivers shall then skip
466a25b988fSLaurent Pinchart * connector creation. For intermediate bridges in the chain, the flag shall
467a25b988fSLaurent Pinchart * be passed to the drm_bridge_attach() call for the downstream bridge.
468a25b988fSLaurent Pinchart * Bridge drivers that implement the new model only shall return an error
469a25b988fSLaurent Pinchart * from their &drm_bridge_funcs.attach handler when the
470a25b988fSLaurent Pinchart * %DRM_BRIDGE_ATTACH_NO_CONNECTOR flag is not set. New display drivers
471a25b988fSLaurent Pinchart * should use the new model, and convert the bridge drivers they use if
472a25b988fSLaurent Pinchart * needed, in order to gradually transition to the new model.
4732331b4e4SArchit Taneja */
4742331b4e4SArchit Taneja
4752331b4e4SArchit Taneja /**
476ea099adfSBoris Brezillon * drm_bridge_chain_mode_fixup - fixup proposed mode for all bridges in the
477862e686cSArchit Taneja * encoder chain
478862e686cSArchit Taneja * @bridge: bridge control structure
479862e686cSArchit Taneja * @mode: desired mode to be set for the bridge
480862e686cSArchit Taneja * @adjusted_mode: updated mode that works for this bridge
481862e686cSArchit Taneja *
4824541d31eSDaniel Vetter * Calls &drm_bridge_funcs.mode_fixup for all the bridges in the
483862e686cSArchit Taneja * encoder chain, starting from the first bridge to the last.
484862e686cSArchit Taneja *
485862e686cSArchit Taneja * Note: the bridge passed should be the one closest to the encoder
486862e686cSArchit Taneja *
487862e686cSArchit Taneja * RETURNS:
488862e686cSArchit Taneja * true on success, false on failure
489862e686cSArchit Taneja */
drm_bridge_chain_mode_fixup(struct drm_bridge * bridge,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)490ea099adfSBoris Brezillon bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge,
491862e686cSArchit Taneja const struct drm_display_mode *mode,
492862e686cSArchit Taneja struct drm_display_mode *adjusted_mode)
493862e686cSArchit Taneja {
49405193dc3SBoris Brezillon struct drm_encoder *encoder;
495862e686cSArchit Taneja
496862e686cSArchit Taneja if (!bridge)
497862e686cSArchit Taneja return true;
498862e686cSArchit Taneja
49905193dc3SBoris Brezillon encoder = bridge->encoder;
50005193dc3SBoris Brezillon list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
50105193dc3SBoris Brezillon if (!bridge->funcs->mode_fixup)
50205193dc3SBoris Brezillon continue;
503862e686cSArchit Taneja
50405193dc3SBoris Brezillon if (!bridge->funcs->mode_fixup(bridge, mode, adjusted_mode))
50505193dc3SBoris Brezillon return false;
50605193dc3SBoris Brezillon }
507862e686cSArchit Taneja
50805193dc3SBoris Brezillon return true;
509862e686cSArchit Taneja }
510ea099adfSBoris Brezillon EXPORT_SYMBOL(drm_bridge_chain_mode_fixup);
511862e686cSArchit Taneja
512862e686cSArchit Taneja /**
513ea099adfSBoris Brezillon * drm_bridge_chain_mode_valid - validate the mode against all bridges in the
514b1240f81SJose Abreu * encoder chain.
515b1240f81SJose Abreu * @bridge: bridge control structure
51612c683e1SLaurent Pinchart * @info: display info against which the mode shall be validated
517b1240f81SJose Abreu * @mode: desired mode to be validated
518b1240f81SJose Abreu *
519b1240f81SJose Abreu * Calls &drm_bridge_funcs.mode_valid for all the bridges in the encoder
520b1240f81SJose Abreu * chain, starting from the first bridge to the last. If at least one bridge
521b1240f81SJose Abreu * does not accept the mode the function returns the error code.
522b1240f81SJose Abreu *
523b1240f81SJose Abreu * Note: the bridge passed should be the one closest to the encoder.
524b1240f81SJose Abreu *
525b1240f81SJose Abreu * RETURNS:
526b1240f81SJose Abreu * MODE_OK on success, drm_mode_status Enum error code on failure
527b1240f81SJose Abreu */
528ea099adfSBoris Brezillon enum drm_mode_status
drm_bridge_chain_mode_valid(struct drm_bridge * bridge,const struct drm_display_info * info,const struct drm_display_mode * mode)529ea099adfSBoris Brezillon drm_bridge_chain_mode_valid(struct drm_bridge *bridge,
53012c683e1SLaurent Pinchart const struct drm_display_info *info,
531b1240f81SJose Abreu const struct drm_display_mode *mode)
532b1240f81SJose Abreu {
53305193dc3SBoris Brezillon struct drm_encoder *encoder;
534b1240f81SJose Abreu
535b1240f81SJose Abreu if (!bridge)
53605193dc3SBoris Brezillon return MODE_OK;
537b1240f81SJose Abreu
53805193dc3SBoris Brezillon encoder = bridge->encoder;
53905193dc3SBoris Brezillon list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
54005193dc3SBoris Brezillon enum drm_mode_status ret;
54105193dc3SBoris Brezillon
54205193dc3SBoris Brezillon if (!bridge->funcs->mode_valid)
54305193dc3SBoris Brezillon continue;
54405193dc3SBoris Brezillon
54512c683e1SLaurent Pinchart ret = bridge->funcs->mode_valid(bridge, info, mode);
546b1240f81SJose Abreu if (ret != MODE_OK)
547b1240f81SJose Abreu return ret;
54805193dc3SBoris Brezillon }
549b1240f81SJose Abreu
55005193dc3SBoris Brezillon return MODE_OK;
551b1240f81SJose Abreu }
552ea099adfSBoris Brezillon EXPORT_SYMBOL(drm_bridge_chain_mode_valid);
553b1240f81SJose Abreu
554b1240f81SJose Abreu /**
555ea099adfSBoris Brezillon * drm_bridge_chain_mode_set - set proposed mode for all bridges in the
556862e686cSArchit Taneja * encoder chain
557862e686cSArchit Taneja * @bridge: bridge control structure
558ea099adfSBoris Brezillon * @mode: desired mode to be set for the encoder chain
559ea099adfSBoris Brezillon * @adjusted_mode: updated mode that works for this encoder chain
560862e686cSArchit Taneja *
5614541d31eSDaniel Vetter * Calls &drm_bridge_funcs.mode_set op for all the bridges in the
562862e686cSArchit Taneja * encoder chain, starting from the first bridge to the last.
563862e686cSArchit Taneja *
564862e686cSArchit Taneja * Note: the bridge passed should be the one closest to the encoder
565862e686cSArchit Taneja */
drm_bridge_chain_mode_set(struct drm_bridge * bridge,const struct drm_display_mode * mode,const struct drm_display_mode * adjusted_mode)566ea099adfSBoris Brezillon void drm_bridge_chain_mode_set(struct drm_bridge *bridge,
56763f8f3baSLaurent Pinchart const struct drm_display_mode *mode,
56863f8f3baSLaurent Pinchart const struct drm_display_mode *adjusted_mode)
569862e686cSArchit Taneja {
57005193dc3SBoris Brezillon struct drm_encoder *encoder;
57105193dc3SBoris Brezillon
572862e686cSArchit Taneja if (!bridge)
573862e686cSArchit Taneja return;
574862e686cSArchit Taneja
57505193dc3SBoris Brezillon encoder = bridge->encoder;
57605193dc3SBoris Brezillon list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
577862e686cSArchit Taneja if (bridge->funcs->mode_set)
578862e686cSArchit Taneja bridge->funcs->mode_set(bridge, mode, adjusted_mode);
57905193dc3SBoris Brezillon }
580862e686cSArchit Taneja }
581ea099adfSBoris Brezillon EXPORT_SYMBOL(drm_bridge_chain_mode_set);
582862e686cSArchit Taneja
583862e686cSArchit Taneja /**
584ea099adfSBoris Brezillon * drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain
5855ade071bSSean Paul * @bridge: bridge control structure
586f3fdbc72SBoris Brezillon * @old_state: old atomic state
5875ade071bSSean Paul *
5885ade071bSSean Paul * Calls &drm_bridge_funcs.atomic_disable (falls back on
5895ade071bSSean Paul * &drm_bridge_funcs.disable) op for all the bridges in the encoder chain,
5905ade071bSSean Paul * starting from the last bridge to the first. These are called before calling
5915ade071bSSean Paul * &drm_encoder_helper_funcs.atomic_disable
5925ade071bSSean Paul *
5935ade071bSSean Paul * Note: the bridge passed should be the one closest to the encoder
5945ade071bSSean Paul */
drm_atomic_bridge_chain_disable(struct drm_bridge * bridge,struct drm_atomic_state * old_state)595ea099adfSBoris Brezillon void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
596f3fdbc72SBoris Brezillon struct drm_atomic_state *old_state)
5975ade071bSSean Paul {
59805193dc3SBoris Brezillon struct drm_encoder *encoder;
59905193dc3SBoris Brezillon struct drm_bridge *iter;
60005193dc3SBoris Brezillon
6015ade071bSSean Paul if (!bridge)
6025ade071bSSean Paul return;
6035ade071bSSean Paul
60405193dc3SBoris Brezillon encoder = bridge->encoder;
60505193dc3SBoris Brezillon list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
60641cf5712SBoris Brezillon if (iter->funcs->atomic_disable) {
60741cf5712SBoris Brezillon struct drm_bridge_state *old_bridge_state;
60841cf5712SBoris Brezillon
60941cf5712SBoris Brezillon old_bridge_state =
61041cf5712SBoris Brezillon drm_atomic_get_old_bridge_state(old_state,
61141cf5712SBoris Brezillon iter);
61241cf5712SBoris Brezillon if (WARN_ON(!old_bridge_state))
61341cf5712SBoris Brezillon return;
61441cf5712SBoris Brezillon
61541cf5712SBoris Brezillon iter->funcs->atomic_disable(iter, old_bridge_state);
61641cf5712SBoris Brezillon } else if (iter->funcs->disable) {
61705193dc3SBoris Brezillon iter->funcs->disable(iter);
61841cf5712SBoris Brezillon }
6195ade071bSSean Paul
62005193dc3SBoris Brezillon if (iter == bridge)
62105193dc3SBoris Brezillon break;
62205193dc3SBoris Brezillon }
6235ade071bSSean Paul }
624ea099adfSBoris Brezillon EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
6255ade071bSSean Paul
drm_atomic_bridge_call_post_disable(struct drm_bridge * bridge,struct drm_atomic_state * old_state)6264fb912e5SDave Stevenson static void drm_atomic_bridge_call_post_disable(struct drm_bridge *bridge,
627f3fdbc72SBoris Brezillon struct drm_atomic_state *old_state)
6285ade071bSSean Paul {
6294fb912e5SDave Stevenson if (old_state && bridge->funcs->atomic_post_disable) {
63041cf5712SBoris Brezillon struct drm_bridge_state *old_bridge_state;
63141cf5712SBoris Brezillon
63241cf5712SBoris Brezillon old_bridge_state =
63341cf5712SBoris Brezillon drm_atomic_get_old_bridge_state(old_state,
63441cf5712SBoris Brezillon bridge);
63541cf5712SBoris Brezillon if (WARN_ON(!old_bridge_state))
63641cf5712SBoris Brezillon return;
63741cf5712SBoris Brezillon
63841cf5712SBoris Brezillon bridge->funcs->atomic_post_disable(bridge,
63941cf5712SBoris Brezillon old_bridge_state);
64041cf5712SBoris Brezillon } else if (bridge->funcs->post_disable) {
6415ade071bSSean Paul bridge->funcs->post_disable(bridge);
64205193dc3SBoris Brezillon }
6435ade071bSSean Paul }
6444fb912e5SDave Stevenson
6454fb912e5SDave Stevenson /**
6464fb912e5SDave Stevenson * drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges
6474fb912e5SDave Stevenson * in the encoder chain
6484fb912e5SDave Stevenson * @bridge: bridge control structure
6494fb912e5SDave Stevenson * @old_state: old atomic state
6504fb912e5SDave Stevenson *
6514fb912e5SDave Stevenson * Calls &drm_bridge_funcs.atomic_post_disable (falls back on
6524fb912e5SDave Stevenson * &drm_bridge_funcs.post_disable) op for all the bridges in the encoder chain,
6534fb912e5SDave Stevenson * starting from the first bridge to the last. These are called after completing
6544fb912e5SDave Stevenson * &drm_encoder_helper_funcs.atomic_disable
6554fb912e5SDave Stevenson *
6564fb912e5SDave Stevenson * If a bridge sets @pre_enable_prev_first, then the @post_disable for that
6574fb912e5SDave Stevenson * bridge will be called before the previous one to reverse the @pre_enable
6584fb912e5SDave Stevenson * calling direction.
6594fb912e5SDave Stevenson *
6604fb912e5SDave Stevenson * Note: the bridge passed should be the one closest to the encoder
6614fb912e5SDave Stevenson */
drm_atomic_bridge_chain_post_disable(struct drm_bridge * bridge,struct drm_atomic_state * old_state)6624fb912e5SDave Stevenson void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
6634fb912e5SDave Stevenson struct drm_atomic_state *old_state)
6644fb912e5SDave Stevenson {
6654fb912e5SDave Stevenson struct drm_encoder *encoder;
6664fb912e5SDave Stevenson struct drm_bridge *next, *limit;
6674fb912e5SDave Stevenson
6684fb912e5SDave Stevenson if (!bridge)
6694fb912e5SDave Stevenson return;
6704fb912e5SDave Stevenson
6714fb912e5SDave Stevenson encoder = bridge->encoder;
6724fb912e5SDave Stevenson
6734fb912e5SDave Stevenson list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
6744fb912e5SDave Stevenson limit = NULL;
6754fb912e5SDave Stevenson
6764fb912e5SDave Stevenson if (!list_is_last(&bridge->chain_node, &encoder->bridge_chain)) {
6774fb912e5SDave Stevenson next = list_next_entry(bridge, chain_node);
6784fb912e5SDave Stevenson
6794fb912e5SDave Stevenson if (next->pre_enable_prev_first) {
6804fb912e5SDave Stevenson /* next bridge had requested that prev
6814fb912e5SDave Stevenson * was enabled first, so disabled last
6824fb912e5SDave Stevenson */
6834fb912e5SDave Stevenson limit = next;
6844fb912e5SDave Stevenson
6854fb912e5SDave Stevenson /* Find the next bridge that has NOT requested
6864fb912e5SDave Stevenson * prev to be enabled first / disabled last
6874fb912e5SDave Stevenson */
6884fb912e5SDave Stevenson list_for_each_entry_from(next, &encoder->bridge_chain,
6894fb912e5SDave Stevenson chain_node) {
6904fb912e5SDave Stevenson if (next->pre_enable_prev_first) {
6914fb912e5SDave Stevenson next = list_prev_entry(next, chain_node);
6924fb912e5SDave Stevenson limit = next;
6934fb912e5SDave Stevenson break;
6944fb912e5SDave Stevenson }
6954fb912e5SDave Stevenson }
6964fb912e5SDave Stevenson
6974fb912e5SDave Stevenson /* Call these bridges in reverse order */
6984fb912e5SDave Stevenson list_for_each_entry_from_reverse(next, &encoder->bridge_chain,
6994fb912e5SDave Stevenson chain_node) {
7004fb912e5SDave Stevenson if (next == bridge)
7014fb912e5SDave Stevenson break;
7024fb912e5SDave Stevenson
7034fb912e5SDave Stevenson drm_atomic_bridge_call_post_disable(next,
7044fb912e5SDave Stevenson old_state);
7054fb912e5SDave Stevenson }
7064fb912e5SDave Stevenson }
7074fb912e5SDave Stevenson }
7084fb912e5SDave Stevenson
7094fb912e5SDave Stevenson drm_atomic_bridge_call_post_disable(bridge, old_state);
7104fb912e5SDave Stevenson
7114fb912e5SDave Stevenson if (limit)
7124fb912e5SDave Stevenson /* Jump all bridges that we have already post_disabled */
7134fb912e5SDave Stevenson bridge = limit;
7144fb912e5SDave Stevenson }
71541cf5712SBoris Brezillon }
716ea099adfSBoris Brezillon EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
7175ade071bSSean Paul
drm_atomic_bridge_call_pre_enable(struct drm_bridge * bridge,struct drm_atomic_state * old_state)7184fb912e5SDave Stevenson static void drm_atomic_bridge_call_pre_enable(struct drm_bridge *bridge,
7194fb912e5SDave Stevenson struct drm_atomic_state *old_state)
7204fb912e5SDave Stevenson {
7214fb912e5SDave Stevenson if (old_state && bridge->funcs->atomic_pre_enable) {
7224fb912e5SDave Stevenson struct drm_bridge_state *old_bridge_state;
7234fb912e5SDave Stevenson
7244fb912e5SDave Stevenson old_bridge_state =
7254fb912e5SDave Stevenson drm_atomic_get_old_bridge_state(old_state,
7264fb912e5SDave Stevenson bridge);
7274fb912e5SDave Stevenson if (WARN_ON(!old_bridge_state))
7284fb912e5SDave Stevenson return;
7294fb912e5SDave Stevenson
7304fb912e5SDave Stevenson bridge->funcs->atomic_pre_enable(bridge, old_bridge_state);
7314fb912e5SDave Stevenson } else if (bridge->funcs->pre_enable) {
7324fb912e5SDave Stevenson bridge->funcs->pre_enable(bridge);
7334fb912e5SDave Stevenson }
7344fb912e5SDave Stevenson }
7354fb912e5SDave Stevenson
7365ade071bSSean Paul /**
737ea099adfSBoris Brezillon * drm_atomic_bridge_chain_pre_enable - prepares for enabling all bridges in
738ea099adfSBoris Brezillon * the encoder chain
7395ade071bSSean Paul * @bridge: bridge control structure
740f3fdbc72SBoris Brezillon * @old_state: old atomic state
7415ade071bSSean Paul *
7425ade071bSSean Paul * Calls &drm_bridge_funcs.atomic_pre_enable (falls back on
7435ade071bSSean Paul * &drm_bridge_funcs.pre_enable) op for all the bridges in the encoder chain,
7445ade071bSSean Paul * starting from the last bridge to the first. These are called before calling
7455ade071bSSean Paul * &drm_encoder_helper_funcs.atomic_enable
7465ade071bSSean Paul *
7474fb912e5SDave Stevenson * If a bridge sets @pre_enable_prev_first, then the pre_enable for the
7484fb912e5SDave Stevenson * prev bridge will be called before pre_enable of this bridge.
7494fb912e5SDave Stevenson *
7505ade071bSSean Paul * Note: the bridge passed should be the one closest to the encoder
7515ade071bSSean Paul */
drm_atomic_bridge_chain_pre_enable(struct drm_bridge * bridge,struct drm_atomic_state * old_state)752ea099adfSBoris Brezillon void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
753f3fdbc72SBoris Brezillon struct drm_atomic_state *old_state)
7545ade071bSSean Paul {
75505193dc3SBoris Brezillon struct drm_encoder *encoder;
7564fb912e5SDave Stevenson struct drm_bridge *iter, *next, *limit;
75705193dc3SBoris Brezillon
7585ade071bSSean Paul if (!bridge)
7595ade071bSSean Paul return;
7605ade071bSSean Paul
76105193dc3SBoris Brezillon encoder = bridge->encoder;
7624fb912e5SDave Stevenson
76305193dc3SBoris Brezillon list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
7644fb912e5SDave Stevenson if (iter->pre_enable_prev_first) {
7654fb912e5SDave Stevenson next = iter;
7664fb912e5SDave Stevenson limit = bridge;
7674fb912e5SDave Stevenson list_for_each_entry_from_reverse(next,
7684fb912e5SDave Stevenson &encoder->bridge_chain,
7694fb912e5SDave Stevenson chain_node) {
7704fb912e5SDave Stevenson if (next == bridge)
7714fb912e5SDave Stevenson break;
77241cf5712SBoris Brezillon
7734fb912e5SDave Stevenson if (!next->pre_enable_prev_first) {
7744fb912e5SDave Stevenson /* Found first bridge that does NOT
7754fb912e5SDave Stevenson * request prev to be enabled first
7764fb912e5SDave Stevenson */
7774fb912e5SDave Stevenson limit = list_prev_entry(next, chain_node);
7784fb912e5SDave Stevenson break;
77941cf5712SBoris Brezillon }
7804fb912e5SDave Stevenson }
7814fb912e5SDave Stevenson
7824fb912e5SDave Stevenson list_for_each_entry_from(next, &encoder->bridge_chain, chain_node) {
7834fb912e5SDave Stevenson /* Call requested prev bridge pre_enable
7844fb912e5SDave Stevenson * in order.
7854fb912e5SDave Stevenson */
7864fb912e5SDave Stevenson if (next == iter)
7874fb912e5SDave Stevenson /* At the first bridge to request prev
7884fb912e5SDave Stevenson * bridges called first.
7894fb912e5SDave Stevenson */
7904fb912e5SDave Stevenson break;
7914fb912e5SDave Stevenson
7924fb912e5SDave Stevenson drm_atomic_bridge_call_pre_enable(next, old_state);
7934fb912e5SDave Stevenson }
7944fb912e5SDave Stevenson }
7954fb912e5SDave Stevenson
7964fb912e5SDave Stevenson drm_atomic_bridge_call_pre_enable(iter, old_state);
7974fb912e5SDave Stevenson
7984fb912e5SDave Stevenson if (iter->pre_enable_prev_first)
7994fb912e5SDave Stevenson /* Jump all bridges that we have already pre_enabled */
8004fb912e5SDave Stevenson iter = limit;
8015ade071bSSean Paul
80205193dc3SBoris Brezillon if (iter == bridge)
80305193dc3SBoris Brezillon break;
80405193dc3SBoris Brezillon }
8055ade071bSSean Paul }
806ea099adfSBoris Brezillon EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
8075ade071bSSean Paul
8085ade071bSSean Paul /**
809ea099adfSBoris Brezillon * drm_atomic_bridge_chain_enable - enables all bridges in the encoder chain
8105ade071bSSean Paul * @bridge: bridge control structure
811f3fdbc72SBoris Brezillon * @old_state: old atomic state
8125ade071bSSean Paul *
8135ade071bSSean Paul * Calls &drm_bridge_funcs.atomic_enable (falls back on
8145ade071bSSean Paul * &drm_bridge_funcs.enable) op for all the bridges in the encoder chain,
8155ade071bSSean Paul * starting from the first bridge to the last. These are called after completing
8165ade071bSSean Paul * &drm_encoder_helper_funcs.atomic_enable
8175ade071bSSean Paul *
8185ade071bSSean Paul * Note: the bridge passed should be the one closest to the encoder
8195ade071bSSean Paul */
drm_atomic_bridge_chain_enable(struct drm_bridge * bridge,struct drm_atomic_state * old_state)820ea099adfSBoris Brezillon void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge,
821f3fdbc72SBoris Brezillon struct drm_atomic_state *old_state)
8225ade071bSSean Paul {
82305193dc3SBoris Brezillon struct drm_encoder *encoder;
82405193dc3SBoris Brezillon
8255ade071bSSean Paul if (!bridge)
8265ade071bSSean Paul return;
8275ade071bSSean Paul
82805193dc3SBoris Brezillon encoder = bridge->encoder;
82905193dc3SBoris Brezillon list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
83041cf5712SBoris Brezillon if (bridge->funcs->atomic_enable) {
83141cf5712SBoris Brezillon struct drm_bridge_state *old_bridge_state;
83241cf5712SBoris Brezillon
83341cf5712SBoris Brezillon old_bridge_state =
83441cf5712SBoris Brezillon drm_atomic_get_old_bridge_state(old_state,
83541cf5712SBoris Brezillon bridge);
83641cf5712SBoris Brezillon if (WARN_ON(!old_bridge_state))
83741cf5712SBoris Brezillon return;
83841cf5712SBoris Brezillon
83941cf5712SBoris Brezillon bridge->funcs->atomic_enable(bridge, old_bridge_state);
84041cf5712SBoris Brezillon } else if (bridge->funcs->enable) {
8415ade071bSSean Paul bridge->funcs->enable(bridge);
84205193dc3SBoris Brezillon }
8435ade071bSSean Paul }
84441cf5712SBoris Brezillon }
845ea099adfSBoris Brezillon EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
8465ade071bSSean Paul
drm_atomic_bridge_check(struct drm_bridge * bridge,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)8475061b8a9SBoris Brezillon static int drm_atomic_bridge_check(struct drm_bridge *bridge,
8485061b8a9SBoris Brezillon struct drm_crtc_state *crtc_state,
8495061b8a9SBoris Brezillon struct drm_connector_state *conn_state)
8505061b8a9SBoris Brezillon {
8515061b8a9SBoris Brezillon if (bridge->funcs->atomic_check) {
8525061b8a9SBoris Brezillon struct drm_bridge_state *bridge_state;
8535061b8a9SBoris Brezillon int ret;
8545061b8a9SBoris Brezillon
8555061b8a9SBoris Brezillon bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
8565061b8a9SBoris Brezillon bridge);
8575061b8a9SBoris Brezillon if (WARN_ON(!bridge_state))
8585061b8a9SBoris Brezillon return -EINVAL;
8595061b8a9SBoris Brezillon
8605061b8a9SBoris Brezillon ret = bridge->funcs->atomic_check(bridge, bridge_state,
8615061b8a9SBoris Brezillon crtc_state, conn_state);
8625061b8a9SBoris Brezillon if (ret)
8635061b8a9SBoris Brezillon return ret;
8645061b8a9SBoris Brezillon } else if (bridge->funcs->mode_fixup) {
8655061b8a9SBoris Brezillon if (!bridge->funcs->mode_fixup(bridge, &crtc_state->mode,
8665061b8a9SBoris Brezillon &crtc_state->adjusted_mode))
8675061b8a9SBoris Brezillon return -EINVAL;
8685061b8a9SBoris Brezillon }
8695061b8a9SBoris Brezillon
8705061b8a9SBoris Brezillon return 0;
8715061b8a9SBoris Brezillon }
8725061b8a9SBoris Brezillon
select_bus_fmt_recursive(struct drm_bridge * first_bridge,struct drm_bridge * cur_bridge,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state,u32 out_bus_fmt)873f32df58aSBoris Brezillon static int select_bus_fmt_recursive(struct drm_bridge *first_bridge,
874f32df58aSBoris Brezillon struct drm_bridge *cur_bridge,
875f32df58aSBoris Brezillon struct drm_crtc_state *crtc_state,
876f32df58aSBoris Brezillon struct drm_connector_state *conn_state,
877f32df58aSBoris Brezillon u32 out_bus_fmt)
878f32df58aSBoris Brezillon {
8797d120273SDan Carpenter unsigned int i, num_in_bus_fmts = 0;
880f32df58aSBoris Brezillon struct drm_bridge_state *cur_state;
881f32df58aSBoris Brezillon struct drm_bridge *prev_bridge;
882f32df58aSBoris Brezillon u32 *in_bus_fmts;
883f32df58aSBoris Brezillon int ret;
884f32df58aSBoris Brezillon
885f32df58aSBoris Brezillon prev_bridge = drm_bridge_get_prev_bridge(cur_bridge);
886f32df58aSBoris Brezillon cur_state = drm_atomic_get_new_bridge_state(crtc_state->state,
887f32df58aSBoris Brezillon cur_bridge);
888f32df58aSBoris Brezillon
889f32df58aSBoris Brezillon /*
890f32df58aSBoris Brezillon * If bus format negotiation is not supported by this bridge, let's
891f32df58aSBoris Brezillon * pass MEDIA_BUS_FMT_FIXED to the previous bridge in the chain and
892f32df58aSBoris Brezillon * hope that it can handle this situation gracefully (by providing
893f32df58aSBoris Brezillon * appropriate default values).
894f32df58aSBoris Brezillon */
895f32df58aSBoris Brezillon if (!cur_bridge->funcs->atomic_get_input_bus_fmts) {
896f32df58aSBoris Brezillon if (cur_bridge != first_bridge) {
897f32df58aSBoris Brezillon ret = select_bus_fmt_recursive(first_bridge,
898f32df58aSBoris Brezillon prev_bridge, crtc_state,
899f32df58aSBoris Brezillon conn_state,
900f32df58aSBoris Brezillon MEDIA_BUS_FMT_FIXED);
901f32df58aSBoris Brezillon if (ret)
902f32df58aSBoris Brezillon return ret;
903f32df58aSBoris Brezillon }
904f32df58aSBoris Brezillon
905f32df58aSBoris Brezillon /*
906f32df58aSBoris Brezillon * Driver does not implement the atomic state hooks, but that's
907f32df58aSBoris Brezillon * fine, as long as it does not access the bridge state.
908f32df58aSBoris Brezillon */
909f32df58aSBoris Brezillon if (cur_state) {
910f32df58aSBoris Brezillon cur_state->input_bus_cfg.format = MEDIA_BUS_FMT_FIXED;
911f32df58aSBoris Brezillon cur_state->output_bus_cfg.format = out_bus_fmt;
912f32df58aSBoris Brezillon }
913f32df58aSBoris Brezillon
914f32df58aSBoris Brezillon return 0;
915f32df58aSBoris Brezillon }
916f32df58aSBoris Brezillon
917f32df58aSBoris Brezillon /*
918f32df58aSBoris Brezillon * If the driver implements ->atomic_get_input_bus_fmts() it
919f32df58aSBoris Brezillon * should also implement the atomic state hooks.
920f32df58aSBoris Brezillon */
921f32df58aSBoris Brezillon if (WARN_ON(!cur_state))
922f32df58aSBoris Brezillon return -EINVAL;
923f32df58aSBoris Brezillon
924f32df58aSBoris Brezillon in_bus_fmts = cur_bridge->funcs->atomic_get_input_bus_fmts(cur_bridge,
925f32df58aSBoris Brezillon cur_state,
926f32df58aSBoris Brezillon crtc_state,
927f32df58aSBoris Brezillon conn_state,
928f32df58aSBoris Brezillon out_bus_fmt,
929f32df58aSBoris Brezillon &num_in_bus_fmts);
930f32df58aSBoris Brezillon if (!num_in_bus_fmts)
931f32df58aSBoris Brezillon return -ENOTSUPP;
932f32df58aSBoris Brezillon else if (!in_bus_fmts)
933f32df58aSBoris Brezillon return -ENOMEM;
934f32df58aSBoris Brezillon
935f32df58aSBoris Brezillon if (first_bridge == cur_bridge) {
936f32df58aSBoris Brezillon cur_state->input_bus_cfg.format = in_bus_fmts[0];
937f32df58aSBoris Brezillon cur_state->output_bus_cfg.format = out_bus_fmt;
938f32df58aSBoris Brezillon kfree(in_bus_fmts);
939f32df58aSBoris Brezillon return 0;
940f32df58aSBoris Brezillon }
941f32df58aSBoris Brezillon
942f32df58aSBoris Brezillon for (i = 0; i < num_in_bus_fmts; i++) {
943f32df58aSBoris Brezillon ret = select_bus_fmt_recursive(first_bridge, prev_bridge,
944f32df58aSBoris Brezillon crtc_state, conn_state,
945f32df58aSBoris Brezillon in_bus_fmts[i]);
946f32df58aSBoris Brezillon if (ret != -ENOTSUPP)
947f32df58aSBoris Brezillon break;
948f32df58aSBoris Brezillon }
949f32df58aSBoris Brezillon
950f32df58aSBoris Brezillon if (!ret) {
951f32df58aSBoris Brezillon cur_state->input_bus_cfg.format = in_bus_fmts[i];
952f32df58aSBoris Brezillon cur_state->output_bus_cfg.format = out_bus_fmt;
953f32df58aSBoris Brezillon }
954f32df58aSBoris Brezillon
955f32df58aSBoris Brezillon kfree(in_bus_fmts);
956f32df58aSBoris Brezillon return ret;
957f32df58aSBoris Brezillon }
958f32df58aSBoris Brezillon
959f32df58aSBoris Brezillon /*
960f32df58aSBoris Brezillon * This function is called by &drm_atomic_bridge_chain_check() just before
961f32df58aSBoris Brezillon * calling &drm_bridge_funcs.atomic_check() on all elements of the chain.
962f32df58aSBoris Brezillon * It performs bus format negotiation between bridge elements. The negotiation
963f32df58aSBoris Brezillon * happens in reverse order, starting from the last element in the chain up to
964f32df58aSBoris Brezillon * @bridge.
965f32df58aSBoris Brezillon *
966f32df58aSBoris Brezillon * Negotiation starts by retrieving supported output bus formats on the last
967f32df58aSBoris Brezillon * bridge element and testing them one by one. The test is recursive, meaning
968f32df58aSBoris Brezillon * that for each tested output format, the whole chain will be walked backward,
969f32df58aSBoris Brezillon * and each element will have to choose an input bus format that can be
970f32df58aSBoris Brezillon * transcoded to the requested output format. When a bridge element does not
971f32df58aSBoris Brezillon * support transcoding into a specific output format -ENOTSUPP is returned and
972f32df58aSBoris Brezillon * the next bridge element will have to try a different format. If none of the
973f32df58aSBoris Brezillon * combinations worked, -ENOTSUPP is returned and the atomic modeset will fail.
974f32df58aSBoris Brezillon *
975f32df58aSBoris Brezillon * This implementation is relying on
976f32df58aSBoris Brezillon * &drm_bridge_funcs.atomic_get_output_bus_fmts() and
977f32df58aSBoris Brezillon * &drm_bridge_funcs.atomic_get_input_bus_fmts() to gather supported
978f32df58aSBoris Brezillon * input/output formats.
979f32df58aSBoris Brezillon *
980f32df58aSBoris Brezillon * When &drm_bridge_funcs.atomic_get_output_bus_fmts() is not implemented by
981f32df58aSBoris Brezillon * the last element of the chain, &drm_atomic_bridge_chain_select_bus_fmts()
982f32df58aSBoris Brezillon * tries a single format: &drm_connector.display_info.bus_formats[0] if
983f32df58aSBoris Brezillon * available, MEDIA_BUS_FMT_FIXED otherwise.
984f32df58aSBoris Brezillon *
985f32df58aSBoris Brezillon * When &drm_bridge_funcs.atomic_get_input_bus_fmts() is not implemented,
986f32df58aSBoris Brezillon * &drm_atomic_bridge_chain_select_bus_fmts() skips the negotiation on the
987f32df58aSBoris Brezillon * bridge element that lacks this hook and asks the previous element in the
988f32df58aSBoris Brezillon * chain to try MEDIA_BUS_FMT_FIXED. It's up to bridge drivers to decide what
989f32df58aSBoris Brezillon * to do in that case (fail if they want to enforce bus format negotiation, or
990f32df58aSBoris Brezillon * provide a reasonable default if they need to support pipelines where not
991f32df58aSBoris Brezillon * all elements support bus format negotiation).
992f32df58aSBoris Brezillon */
993f32df58aSBoris Brezillon static int
drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge * bridge,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)994f32df58aSBoris Brezillon drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge,
995f32df58aSBoris Brezillon struct drm_crtc_state *crtc_state,
996f32df58aSBoris Brezillon struct drm_connector_state *conn_state)
997f32df58aSBoris Brezillon {
998f32df58aSBoris Brezillon struct drm_connector *conn = conn_state->connector;
999f32df58aSBoris Brezillon struct drm_encoder *encoder = bridge->encoder;
1000f32df58aSBoris Brezillon struct drm_bridge_state *last_bridge_state;
10017d120273SDan Carpenter unsigned int i, num_out_bus_fmts = 0;
1002f32df58aSBoris Brezillon struct drm_bridge *last_bridge;
1003f32df58aSBoris Brezillon u32 *out_bus_fmts;
1004f32df58aSBoris Brezillon int ret = 0;
1005f32df58aSBoris Brezillon
1006f32df58aSBoris Brezillon last_bridge = list_last_entry(&encoder->bridge_chain,
1007f32df58aSBoris Brezillon struct drm_bridge, chain_node);
1008f32df58aSBoris Brezillon last_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
1009f32df58aSBoris Brezillon last_bridge);
1010f32df58aSBoris Brezillon
1011f32df58aSBoris Brezillon if (last_bridge->funcs->atomic_get_output_bus_fmts) {
1012f32df58aSBoris Brezillon const struct drm_bridge_funcs *funcs = last_bridge->funcs;
1013f32df58aSBoris Brezillon
1014f32df58aSBoris Brezillon /*
1015f32df58aSBoris Brezillon * If the driver implements ->atomic_get_output_bus_fmts() it
1016f32df58aSBoris Brezillon * should also implement the atomic state hooks.
1017f32df58aSBoris Brezillon */
1018f32df58aSBoris Brezillon if (WARN_ON(!last_bridge_state))
1019f32df58aSBoris Brezillon return -EINVAL;
1020f32df58aSBoris Brezillon
1021f32df58aSBoris Brezillon out_bus_fmts = funcs->atomic_get_output_bus_fmts(last_bridge,
1022f32df58aSBoris Brezillon last_bridge_state,
1023f32df58aSBoris Brezillon crtc_state,
1024f32df58aSBoris Brezillon conn_state,
1025f32df58aSBoris Brezillon &num_out_bus_fmts);
1026f32df58aSBoris Brezillon if (!num_out_bus_fmts)
1027f32df58aSBoris Brezillon return -ENOTSUPP;
1028f32df58aSBoris Brezillon else if (!out_bus_fmts)
1029f32df58aSBoris Brezillon return -ENOMEM;
1030f32df58aSBoris Brezillon } else {
1031f32df58aSBoris Brezillon num_out_bus_fmts = 1;
1032f32df58aSBoris Brezillon out_bus_fmts = kmalloc(sizeof(*out_bus_fmts), GFP_KERNEL);
1033f32df58aSBoris Brezillon if (!out_bus_fmts)
1034f32df58aSBoris Brezillon return -ENOMEM;
1035f32df58aSBoris Brezillon
1036f32df58aSBoris Brezillon if (conn->display_info.num_bus_formats &&
1037f32df58aSBoris Brezillon conn->display_info.bus_formats)
1038f32df58aSBoris Brezillon out_bus_fmts[0] = conn->display_info.bus_formats[0];
1039f32df58aSBoris Brezillon else
1040f32df58aSBoris Brezillon out_bus_fmts[0] = MEDIA_BUS_FMT_FIXED;
1041f32df58aSBoris Brezillon }
1042f32df58aSBoris Brezillon
1043f32df58aSBoris Brezillon for (i = 0; i < num_out_bus_fmts; i++) {
1044f32df58aSBoris Brezillon ret = select_bus_fmt_recursive(bridge, last_bridge, crtc_state,
1045f32df58aSBoris Brezillon conn_state, out_bus_fmts[i]);
1046f32df58aSBoris Brezillon if (ret != -ENOTSUPP)
1047f32df58aSBoris Brezillon break;
1048f32df58aSBoris Brezillon }
1049f32df58aSBoris Brezillon
1050f32df58aSBoris Brezillon kfree(out_bus_fmts);
1051f32df58aSBoris Brezillon
1052f32df58aSBoris Brezillon return ret;
1053f32df58aSBoris Brezillon }
1054f32df58aSBoris Brezillon
1055f32df58aSBoris Brezillon static void
drm_atomic_bridge_propagate_bus_flags(struct drm_bridge * bridge,struct drm_connector * conn,struct drm_atomic_state * state)1056f32df58aSBoris Brezillon drm_atomic_bridge_propagate_bus_flags(struct drm_bridge *bridge,
1057f32df58aSBoris Brezillon struct drm_connector *conn,
1058f32df58aSBoris Brezillon struct drm_atomic_state *state)
1059f32df58aSBoris Brezillon {
1060f32df58aSBoris Brezillon struct drm_bridge_state *bridge_state, *next_bridge_state;
1061f32df58aSBoris Brezillon struct drm_bridge *next_bridge;
1062f32df58aSBoris Brezillon u32 output_flags = 0;
1063f32df58aSBoris Brezillon
1064f32df58aSBoris Brezillon bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
1065f32df58aSBoris Brezillon
1066f32df58aSBoris Brezillon /* No bridge state attached to this bridge => nothing to propagate. */
1067f32df58aSBoris Brezillon if (!bridge_state)
1068f32df58aSBoris Brezillon return;
1069f32df58aSBoris Brezillon
1070f32df58aSBoris Brezillon next_bridge = drm_bridge_get_next_bridge(bridge);
1071f32df58aSBoris Brezillon
1072f32df58aSBoris Brezillon /*
1073f32df58aSBoris Brezillon * Let's try to apply the most common case here, that is, propagate
1074f32df58aSBoris Brezillon * display_info flags for the last bridge, and propagate the input
1075f32df58aSBoris Brezillon * flags of the next bridge element to the output end of the current
1076f32df58aSBoris Brezillon * bridge when the bridge is not the last one.
1077f32df58aSBoris Brezillon * There are exceptions to this rule, like when signal inversion is
1078f32df58aSBoris Brezillon * happening at the board level, but that's something drivers can deal
1079f32df58aSBoris Brezillon * with from their &drm_bridge_funcs.atomic_check() implementation by
1080f32df58aSBoris Brezillon * simply overriding the flags value we've set here.
1081f32df58aSBoris Brezillon */
1082f32df58aSBoris Brezillon if (!next_bridge) {
1083f32df58aSBoris Brezillon output_flags = conn->display_info.bus_flags;
1084f32df58aSBoris Brezillon } else {
1085f32df58aSBoris Brezillon next_bridge_state = drm_atomic_get_new_bridge_state(state,
1086f32df58aSBoris Brezillon next_bridge);
1087f32df58aSBoris Brezillon /*
1088f32df58aSBoris Brezillon * No bridge state attached to the next bridge, just leave the
1089f32df58aSBoris Brezillon * flags to 0.
1090f32df58aSBoris Brezillon */
1091f32df58aSBoris Brezillon if (next_bridge_state)
1092f32df58aSBoris Brezillon output_flags = next_bridge_state->input_bus_cfg.flags;
1093f32df58aSBoris Brezillon }
1094f32df58aSBoris Brezillon
1095f32df58aSBoris Brezillon bridge_state->output_bus_cfg.flags = output_flags;
1096f32df58aSBoris Brezillon
1097f32df58aSBoris Brezillon /*
10980ae865efSCai Huoqing * Propagate the output flags to the input end of the bridge. Again, it's
1099f32df58aSBoris Brezillon * not necessarily what all bridges want, but that's what most of them
1100f32df58aSBoris Brezillon * do, and by doing that by default we avoid forcing drivers to
1101f32df58aSBoris Brezillon * duplicate the "dummy propagation" logic.
1102f32df58aSBoris Brezillon */
1103f32df58aSBoris Brezillon bridge_state->input_bus_cfg.flags = output_flags;
1104f32df58aSBoris Brezillon }
1105f32df58aSBoris Brezillon
11065061b8a9SBoris Brezillon /**
11075061b8a9SBoris Brezillon * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain
11085061b8a9SBoris Brezillon * @bridge: bridge control structure
11095061b8a9SBoris Brezillon * @crtc_state: new CRTC state
11105061b8a9SBoris Brezillon * @conn_state: new connector state
11115061b8a9SBoris Brezillon *
1112f32df58aSBoris Brezillon * First trigger a bus format negotiation before calling
1113f32df58aSBoris Brezillon * &drm_bridge_funcs.atomic_check() (falls back on
11145061b8a9SBoris Brezillon * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain,
11155061b8a9SBoris Brezillon * starting from the last bridge to the first. These are called before calling
11165061b8a9SBoris Brezillon * &drm_encoder_helper_funcs.atomic_check()
11175061b8a9SBoris Brezillon *
11185061b8a9SBoris Brezillon * RETURNS:
11195061b8a9SBoris Brezillon * 0 on success, a negative error code on failure
11205061b8a9SBoris Brezillon */
drm_atomic_bridge_chain_check(struct drm_bridge * bridge,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)11215061b8a9SBoris Brezillon int drm_atomic_bridge_chain_check(struct drm_bridge *bridge,
11225061b8a9SBoris Brezillon struct drm_crtc_state *crtc_state,
11235061b8a9SBoris Brezillon struct drm_connector_state *conn_state)
11245061b8a9SBoris Brezillon {
1125f32df58aSBoris Brezillon struct drm_connector *conn = conn_state->connector;
11265061b8a9SBoris Brezillon struct drm_encoder *encoder;
11275061b8a9SBoris Brezillon struct drm_bridge *iter;
1128f32df58aSBoris Brezillon int ret;
11295061b8a9SBoris Brezillon
11305061b8a9SBoris Brezillon if (!bridge)
11315061b8a9SBoris Brezillon return 0;
11325061b8a9SBoris Brezillon
1133f32df58aSBoris Brezillon ret = drm_atomic_bridge_chain_select_bus_fmts(bridge, crtc_state,
1134f32df58aSBoris Brezillon conn_state);
1135f32df58aSBoris Brezillon if (ret)
1136f32df58aSBoris Brezillon return ret;
1137f32df58aSBoris Brezillon
11385061b8a9SBoris Brezillon encoder = bridge->encoder;
11395061b8a9SBoris Brezillon list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
11405061b8a9SBoris Brezillon int ret;
11415061b8a9SBoris Brezillon
1142f32df58aSBoris Brezillon /*
1143f32df58aSBoris Brezillon * Bus flags are propagated by default. If a bridge needs to
1144f32df58aSBoris Brezillon * tweak the input bus flags for any reason, it should happen
1145f32df58aSBoris Brezillon * in its &drm_bridge_funcs.atomic_check() implementation such
1146f32df58aSBoris Brezillon * that preceding bridges in the chain can propagate the new
1147f32df58aSBoris Brezillon * bus flags.
1148f32df58aSBoris Brezillon */
1149f32df58aSBoris Brezillon drm_atomic_bridge_propagate_bus_flags(iter, conn,
1150f32df58aSBoris Brezillon crtc_state->state);
1151f32df58aSBoris Brezillon
11525061b8a9SBoris Brezillon ret = drm_atomic_bridge_check(iter, crtc_state, conn_state);
11535061b8a9SBoris Brezillon if (ret)
11545061b8a9SBoris Brezillon return ret;
11555061b8a9SBoris Brezillon
11565061b8a9SBoris Brezillon if (iter == bridge)
11575061b8a9SBoris Brezillon break;
11585061b8a9SBoris Brezillon }
11595061b8a9SBoris Brezillon
11605061b8a9SBoris Brezillon return 0;
11615061b8a9SBoris Brezillon }
11625061b8a9SBoris Brezillon EXPORT_SYMBOL(drm_atomic_bridge_chain_check);
11635061b8a9SBoris Brezillon
116411f6c4b1SLaurent Pinchart /**
116511f6c4b1SLaurent Pinchart * drm_bridge_detect - check if anything is attached to the bridge output
116611f6c4b1SLaurent Pinchart * @bridge: bridge control structure
116711f6c4b1SLaurent Pinchart *
116811f6c4b1SLaurent Pinchart * If the bridge supports output detection, as reported by the
116911f6c4b1SLaurent Pinchart * DRM_BRIDGE_OP_DETECT bridge ops flag, call &drm_bridge_funcs.detect for the
117011f6c4b1SLaurent Pinchart * bridge and return the connection status. Otherwise return
117111f6c4b1SLaurent Pinchart * connector_status_unknown.
117211f6c4b1SLaurent Pinchart *
117311f6c4b1SLaurent Pinchart * RETURNS:
117411f6c4b1SLaurent Pinchart * The detection status on success, or connector_status_unknown if the bridge
117511f6c4b1SLaurent Pinchart * doesn't support output detection.
117611f6c4b1SLaurent Pinchart */
drm_bridge_detect(struct drm_bridge * bridge)117711f6c4b1SLaurent Pinchart enum drm_connector_status drm_bridge_detect(struct drm_bridge *bridge)
117811f6c4b1SLaurent Pinchart {
117911f6c4b1SLaurent Pinchart if (!(bridge->ops & DRM_BRIDGE_OP_DETECT))
118011f6c4b1SLaurent Pinchart return connector_status_unknown;
118111f6c4b1SLaurent Pinchart
118211f6c4b1SLaurent Pinchart return bridge->funcs->detect(bridge);
118311f6c4b1SLaurent Pinchart }
118411f6c4b1SLaurent Pinchart EXPORT_SYMBOL_GPL(drm_bridge_detect);
118511f6c4b1SLaurent Pinchart
118611f6c4b1SLaurent Pinchart /**
118711f6c4b1SLaurent Pinchart * drm_bridge_get_modes - fill all modes currently valid for the sink into the
118811f6c4b1SLaurent Pinchart * @connector
118911f6c4b1SLaurent Pinchart * @bridge: bridge control structure
119011f6c4b1SLaurent Pinchart * @connector: the connector to fill with modes
119111f6c4b1SLaurent Pinchart *
119211f6c4b1SLaurent Pinchart * If the bridge supports output modes retrieval, as reported by the
119311f6c4b1SLaurent Pinchart * DRM_BRIDGE_OP_MODES bridge ops flag, call &drm_bridge_funcs.get_modes to
119411f6c4b1SLaurent Pinchart * fill the connector with all valid modes and return the number of modes
119511f6c4b1SLaurent Pinchart * added. Otherwise return 0.
119611f6c4b1SLaurent Pinchart *
119711f6c4b1SLaurent Pinchart * RETURNS:
119811f6c4b1SLaurent Pinchart * The number of modes added to the connector.
119911f6c4b1SLaurent Pinchart */
drm_bridge_get_modes(struct drm_bridge * bridge,struct drm_connector * connector)120011f6c4b1SLaurent Pinchart int drm_bridge_get_modes(struct drm_bridge *bridge,
120111f6c4b1SLaurent Pinchart struct drm_connector *connector)
120211f6c4b1SLaurent Pinchart {
120311f6c4b1SLaurent Pinchart if (!(bridge->ops & DRM_BRIDGE_OP_MODES))
120411f6c4b1SLaurent Pinchart return 0;
120511f6c4b1SLaurent Pinchart
120611f6c4b1SLaurent Pinchart return bridge->funcs->get_modes(bridge, connector);
120711f6c4b1SLaurent Pinchart }
120811f6c4b1SLaurent Pinchart EXPORT_SYMBOL_GPL(drm_bridge_get_modes);
120911f6c4b1SLaurent Pinchart
121011f6c4b1SLaurent Pinchart /**
12112b6aaf7bSJani Nikula * drm_bridge_edid_read - read the EDID data of the connected display
12122b6aaf7bSJani Nikula * @bridge: bridge control structure
12132b6aaf7bSJani Nikula * @connector: the connector to read EDID for
12142b6aaf7bSJani Nikula *
12152b6aaf7bSJani Nikula * If the bridge supports output EDID retrieval, as reported by the
12162b6aaf7bSJani Nikula * DRM_BRIDGE_OP_EDID bridge ops flag, call &drm_bridge_funcs.edid_read to get
12172b6aaf7bSJani Nikula * the EDID and return it. Otherwise return NULL.
12182b6aaf7bSJani Nikula *
12192b6aaf7bSJani Nikula * If &drm_bridge_funcs.edid_read is not set, fall back to using
12202b6aaf7bSJani Nikula * drm_bridge_get_edid() and wrapping it in struct drm_edid.
12212b6aaf7bSJani Nikula *
12222b6aaf7bSJani Nikula * RETURNS:
12232b6aaf7bSJani Nikula * The retrieved EDID on success, or NULL otherwise.
12242b6aaf7bSJani Nikula */
drm_bridge_edid_read(struct drm_bridge * bridge,struct drm_connector * connector)12252b6aaf7bSJani Nikula const struct drm_edid *drm_bridge_edid_read(struct drm_bridge *bridge,
12262b6aaf7bSJani Nikula struct drm_connector *connector)
12272b6aaf7bSJani Nikula {
12282b6aaf7bSJani Nikula if (!(bridge->ops & DRM_BRIDGE_OP_EDID))
12292b6aaf7bSJani Nikula return NULL;
12302b6aaf7bSJani Nikula
12312b6aaf7bSJani Nikula /* Transitional: Fall back to ->get_edid. */
12322b6aaf7bSJani Nikula if (!bridge->funcs->edid_read) {
12332b6aaf7bSJani Nikula const struct drm_edid *drm_edid;
12342b6aaf7bSJani Nikula struct edid *edid;
12352b6aaf7bSJani Nikula
12362b6aaf7bSJani Nikula edid = drm_bridge_get_edid(bridge, connector);
12372b6aaf7bSJani Nikula if (!edid)
12382b6aaf7bSJani Nikula return NULL;
12392b6aaf7bSJani Nikula
12402b6aaf7bSJani Nikula drm_edid = drm_edid_alloc(edid, (edid->extensions + 1) * EDID_LENGTH);
12412b6aaf7bSJani Nikula
12422b6aaf7bSJani Nikula kfree(edid);
12432b6aaf7bSJani Nikula
12442b6aaf7bSJani Nikula return drm_edid;
12452b6aaf7bSJani Nikula }
12462b6aaf7bSJani Nikula
12472b6aaf7bSJani Nikula return bridge->funcs->edid_read(bridge, connector);
12482b6aaf7bSJani Nikula }
12492b6aaf7bSJani Nikula EXPORT_SYMBOL_GPL(drm_bridge_edid_read);
12502b6aaf7bSJani Nikula
12512b6aaf7bSJani Nikula /**
125211f6c4b1SLaurent Pinchart * drm_bridge_get_edid - get the EDID data of the connected display
125311f6c4b1SLaurent Pinchart * @bridge: bridge control structure
125411f6c4b1SLaurent Pinchart * @connector: the connector to read EDID for
125511f6c4b1SLaurent Pinchart *
125611f6c4b1SLaurent Pinchart * If the bridge supports output EDID retrieval, as reported by the
125711f6c4b1SLaurent Pinchart * DRM_BRIDGE_OP_EDID bridge ops flag, call &drm_bridge_funcs.get_edid to
125811d3cf80SLaurent Pinchart * get the EDID and return it. Otherwise return NULL.
125911f6c4b1SLaurent Pinchart *
12602b6aaf7bSJani Nikula * Deprecated. Prefer using drm_bridge_edid_read().
12612b6aaf7bSJani Nikula *
126211f6c4b1SLaurent Pinchart * RETURNS:
126311d3cf80SLaurent Pinchart * The retrieved EDID on success, or NULL otherwise.
126411f6c4b1SLaurent Pinchart */
drm_bridge_get_edid(struct drm_bridge * bridge,struct drm_connector * connector)126511f6c4b1SLaurent Pinchart struct edid *drm_bridge_get_edid(struct drm_bridge *bridge,
126611f6c4b1SLaurent Pinchart struct drm_connector *connector)
126711f6c4b1SLaurent Pinchart {
126811f6c4b1SLaurent Pinchart if (!(bridge->ops & DRM_BRIDGE_OP_EDID))
126911d3cf80SLaurent Pinchart return NULL;
127011f6c4b1SLaurent Pinchart
127111f6c4b1SLaurent Pinchart return bridge->funcs->get_edid(bridge, connector);
127211f6c4b1SLaurent Pinchart }
127311f6c4b1SLaurent Pinchart EXPORT_SYMBOL_GPL(drm_bridge_get_edid);
127411f6c4b1SLaurent Pinchart
127511f6c4b1SLaurent Pinchart /**
127611f6c4b1SLaurent Pinchart * drm_bridge_hpd_enable - enable hot plug detection for the bridge
127711f6c4b1SLaurent Pinchart * @bridge: bridge control structure
127811f6c4b1SLaurent Pinchart * @cb: hot-plug detection callback
127911f6c4b1SLaurent Pinchart * @data: data to be passed to the hot-plug detection callback
128011f6c4b1SLaurent Pinchart *
128111f6c4b1SLaurent Pinchart * Call &drm_bridge_funcs.hpd_enable if implemented and register the given @cb
128211f6c4b1SLaurent Pinchart * and @data as hot plug notification callback. From now on the @cb will be
128311f6c4b1SLaurent Pinchart * called with @data when an output status change is detected by the bridge,
128411f6c4b1SLaurent Pinchart * until hot plug notification gets disabled with drm_bridge_hpd_disable().
128511f6c4b1SLaurent Pinchart *
128611f6c4b1SLaurent Pinchart * Hot plug detection is supported only if the DRM_BRIDGE_OP_HPD flag is set in
128711f6c4b1SLaurent Pinchart * bridge->ops. This function shall not be called when the flag is not set.
128811f6c4b1SLaurent Pinchart *
128911f6c4b1SLaurent Pinchart * Only one hot plug detection callback can be registered at a time, it is an
129011f6c4b1SLaurent Pinchart * error to call this function when hot plug detection is already enabled for
129111f6c4b1SLaurent Pinchart * the bridge.
129211f6c4b1SLaurent Pinchart */
drm_bridge_hpd_enable(struct drm_bridge * bridge,void (* cb)(void * data,enum drm_connector_status status),void * data)129311f6c4b1SLaurent Pinchart void drm_bridge_hpd_enable(struct drm_bridge *bridge,
129411f6c4b1SLaurent Pinchart void (*cb)(void *data,
129511f6c4b1SLaurent Pinchart enum drm_connector_status status),
129611f6c4b1SLaurent Pinchart void *data)
129711f6c4b1SLaurent Pinchart {
129811f6c4b1SLaurent Pinchart if (!(bridge->ops & DRM_BRIDGE_OP_HPD))
129911f6c4b1SLaurent Pinchart return;
130011f6c4b1SLaurent Pinchart
130111f6c4b1SLaurent Pinchart mutex_lock(&bridge->hpd_mutex);
130211f6c4b1SLaurent Pinchart
130311f6c4b1SLaurent Pinchart if (WARN(bridge->hpd_cb, "Hot plug detection already enabled\n"))
130411f6c4b1SLaurent Pinchart goto unlock;
130511f6c4b1SLaurent Pinchart
130611f6c4b1SLaurent Pinchart bridge->hpd_cb = cb;
130711f6c4b1SLaurent Pinchart bridge->hpd_data = data;
130811f6c4b1SLaurent Pinchart
130911f6c4b1SLaurent Pinchart if (bridge->funcs->hpd_enable)
131011f6c4b1SLaurent Pinchart bridge->funcs->hpd_enable(bridge);
131111f6c4b1SLaurent Pinchart
131211f6c4b1SLaurent Pinchart unlock:
131311f6c4b1SLaurent Pinchart mutex_unlock(&bridge->hpd_mutex);
131411f6c4b1SLaurent Pinchart }
131511f6c4b1SLaurent Pinchart EXPORT_SYMBOL_GPL(drm_bridge_hpd_enable);
131611f6c4b1SLaurent Pinchart
131711f6c4b1SLaurent Pinchart /**
131811f6c4b1SLaurent Pinchart * drm_bridge_hpd_disable - disable hot plug detection for the bridge
131911f6c4b1SLaurent Pinchart * @bridge: bridge control structure
132011f6c4b1SLaurent Pinchart *
132111f6c4b1SLaurent Pinchart * Call &drm_bridge_funcs.hpd_disable if implemented and unregister the hot
132211f6c4b1SLaurent Pinchart * plug detection callback previously registered with drm_bridge_hpd_enable().
132311f6c4b1SLaurent Pinchart * Once this function returns the callback will not be called by the bridge
132411f6c4b1SLaurent Pinchart * when an output status change occurs.
132511f6c4b1SLaurent Pinchart *
132611f6c4b1SLaurent Pinchart * Hot plug detection is supported only if the DRM_BRIDGE_OP_HPD flag is set in
132711f6c4b1SLaurent Pinchart * bridge->ops. This function shall not be called when the flag is not set.
132811f6c4b1SLaurent Pinchart */
drm_bridge_hpd_disable(struct drm_bridge * bridge)132911f6c4b1SLaurent Pinchart void drm_bridge_hpd_disable(struct drm_bridge *bridge)
133011f6c4b1SLaurent Pinchart {
133111f6c4b1SLaurent Pinchart if (!(bridge->ops & DRM_BRIDGE_OP_HPD))
133211f6c4b1SLaurent Pinchart return;
133311f6c4b1SLaurent Pinchart
133411f6c4b1SLaurent Pinchart mutex_lock(&bridge->hpd_mutex);
133511f6c4b1SLaurent Pinchart if (bridge->funcs->hpd_disable)
133611f6c4b1SLaurent Pinchart bridge->funcs->hpd_disable(bridge);
133711f6c4b1SLaurent Pinchart
133811f6c4b1SLaurent Pinchart bridge->hpd_cb = NULL;
133911f6c4b1SLaurent Pinchart bridge->hpd_data = NULL;
134011f6c4b1SLaurent Pinchart mutex_unlock(&bridge->hpd_mutex);
134111f6c4b1SLaurent Pinchart }
134211f6c4b1SLaurent Pinchart EXPORT_SYMBOL_GPL(drm_bridge_hpd_disable);
134311f6c4b1SLaurent Pinchart
134411f6c4b1SLaurent Pinchart /**
134511f6c4b1SLaurent Pinchart * drm_bridge_hpd_notify - notify hot plug detection events
134611f6c4b1SLaurent Pinchart * @bridge: bridge control structure
134711f6c4b1SLaurent Pinchart * @status: output connection status
134811f6c4b1SLaurent Pinchart *
134911f6c4b1SLaurent Pinchart * Bridge drivers shall call this function to report hot plug events when they
135011f6c4b1SLaurent Pinchart * detect a change in the output status, when hot plug detection has been
135111f6c4b1SLaurent Pinchart * enabled by drm_bridge_hpd_enable().
135211f6c4b1SLaurent Pinchart *
135311f6c4b1SLaurent Pinchart * This function shall be called in a context that can sleep.
135411f6c4b1SLaurent Pinchart */
drm_bridge_hpd_notify(struct drm_bridge * bridge,enum drm_connector_status status)135511f6c4b1SLaurent Pinchart void drm_bridge_hpd_notify(struct drm_bridge *bridge,
135611f6c4b1SLaurent Pinchart enum drm_connector_status status)
135711f6c4b1SLaurent Pinchart {
135811f6c4b1SLaurent Pinchart mutex_lock(&bridge->hpd_mutex);
135911f6c4b1SLaurent Pinchart if (bridge->hpd_cb)
136011f6c4b1SLaurent Pinchart bridge->hpd_cb(bridge->hpd_data, status);
136111f6c4b1SLaurent Pinchart mutex_unlock(&bridge->hpd_mutex);
136211f6c4b1SLaurent Pinchart }
136311f6c4b1SLaurent Pinchart EXPORT_SYMBOL_GPL(drm_bridge_hpd_notify);
136411f6c4b1SLaurent Pinchart
13653d3f8b1fSAjay Kumar #ifdef CONFIG_OF
13662331b4e4SArchit Taneja /**
13672331b4e4SArchit Taneja * of_drm_find_bridge - find the bridge corresponding to the device node in
13682331b4e4SArchit Taneja * the global bridge list
13692331b4e4SArchit Taneja *
13702331b4e4SArchit Taneja * @np: device node
13712331b4e4SArchit Taneja *
13722331b4e4SArchit Taneja * RETURNS:
13732331b4e4SArchit Taneja * drm_bridge control struct on success, NULL on failure
13742331b4e4SArchit Taneja */
of_drm_find_bridge(struct device_node * np)13753d3f8b1fSAjay Kumar struct drm_bridge *of_drm_find_bridge(struct device_node *np)
13763d3f8b1fSAjay Kumar {
13773d3f8b1fSAjay Kumar struct drm_bridge *bridge;
13783d3f8b1fSAjay Kumar
13793d3f8b1fSAjay Kumar mutex_lock(&bridge_lock);
13803d3f8b1fSAjay Kumar
13813d3f8b1fSAjay Kumar list_for_each_entry(bridge, &bridge_list, list) {
13823d3f8b1fSAjay Kumar if (bridge->of_node == np) {
13833d3f8b1fSAjay Kumar mutex_unlock(&bridge_lock);
13843d3f8b1fSAjay Kumar return bridge;
13853d3f8b1fSAjay Kumar }
13863d3f8b1fSAjay Kumar }
13873d3f8b1fSAjay Kumar
13883d3f8b1fSAjay Kumar mutex_unlock(&bridge_lock);
13893d3f8b1fSAjay Kumar return NULL;
13903d3f8b1fSAjay Kumar }
13913d3f8b1fSAjay Kumar EXPORT_SYMBOL(of_drm_find_bridge);
13923d3f8b1fSAjay Kumar #endif
13933d3f8b1fSAjay Kumar
13948e4bb53cSTomi Valkeinen #ifdef CONFIG_DEBUG_FS
drm_bridge_chains_info(struct seq_file * m,void * data)13958e4bb53cSTomi Valkeinen static int drm_bridge_chains_info(struct seq_file *m, void *data)
13968e4bb53cSTomi Valkeinen {
13978e4bb53cSTomi Valkeinen struct drm_debugfs_entry *entry = m->private;
13988e4bb53cSTomi Valkeinen struct drm_device *dev = entry->dev;
13998e4bb53cSTomi Valkeinen struct drm_printer p = drm_seq_file_printer(m);
14008e4bb53cSTomi Valkeinen struct drm_mode_config *config = &dev->mode_config;
14018e4bb53cSTomi Valkeinen struct drm_encoder *encoder;
14028e4bb53cSTomi Valkeinen unsigned int bridge_idx = 0;
14038e4bb53cSTomi Valkeinen
14048e4bb53cSTomi Valkeinen list_for_each_entry(encoder, &config->encoder_list, head) {
14058e4bb53cSTomi Valkeinen struct drm_bridge *bridge;
14068e4bb53cSTomi Valkeinen
14078e4bb53cSTomi Valkeinen drm_printf(&p, "encoder[%u]\n", encoder->base.id);
14088e4bb53cSTomi Valkeinen
14098e4bb53cSTomi Valkeinen drm_for_each_bridge_in_chain(encoder, bridge) {
14108e4bb53cSTomi Valkeinen drm_printf(&p, "\tbridge[%u] type: %u, ops: %#x",
14118e4bb53cSTomi Valkeinen bridge_idx, bridge->type, bridge->ops);
14128e4bb53cSTomi Valkeinen
14138e4bb53cSTomi Valkeinen #ifdef CONFIG_OF
14148e4bb53cSTomi Valkeinen if (bridge->of_node)
14158e4bb53cSTomi Valkeinen drm_printf(&p, ", OF: %pOFfc", bridge->of_node);
14168e4bb53cSTomi Valkeinen #endif
14178e4bb53cSTomi Valkeinen
14188e4bb53cSTomi Valkeinen drm_printf(&p, "\n");
14198e4bb53cSTomi Valkeinen
14208e4bb53cSTomi Valkeinen bridge_idx++;
14218e4bb53cSTomi Valkeinen }
14228e4bb53cSTomi Valkeinen }
14238e4bb53cSTomi Valkeinen
14248e4bb53cSTomi Valkeinen return 0;
14258e4bb53cSTomi Valkeinen }
14268e4bb53cSTomi Valkeinen
14278e4bb53cSTomi Valkeinen static const struct drm_debugfs_info drm_bridge_debugfs_list[] = {
14288e4bb53cSTomi Valkeinen { "bridge_chains", drm_bridge_chains_info, 0 },
14298e4bb53cSTomi Valkeinen };
14308e4bb53cSTomi Valkeinen
drm_bridge_debugfs_init(struct drm_minor * minor)14318e4bb53cSTomi Valkeinen void drm_bridge_debugfs_init(struct drm_minor *minor)
14328e4bb53cSTomi Valkeinen {
14338e4bb53cSTomi Valkeinen drm_debugfs_add_files(minor->dev, drm_bridge_debugfs_list,
14348e4bb53cSTomi Valkeinen ARRAY_SIZE(drm_bridge_debugfs_list));
14358e4bb53cSTomi Valkeinen }
14368e4bb53cSTomi Valkeinen #endif
14378e4bb53cSTomi Valkeinen
14383d3f8b1fSAjay Kumar MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>");
14393d3f8b1fSAjay Kumar MODULE_DESCRIPTION("DRM bridge infrastructure");
14403d3f8b1fSAjay Kumar MODULE_LICENSE("GPL and additional rights");
1441