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