1 From 2c8b6954e6168d56cc6d35f5f6d075c826a9b8e1 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Thu, 16 Dec 2021 15:25:35 +0000
4 Subject: [PATCH] drm/bridge: Introduce pre_enable_upstream_first to
5 alter bridge init order
7 DSI sink devices typically want the DSI host powered up and configured
8 before they are powered up. pre_enable is the place this would normally
9 happen, but they are called in reverse order from panel/connector towards
10 the encoder, which is the "wrong" order.
12 Add a new flag pre_enable_upstream_first that any bridge can set
13 to swap the order of pre_enable (and post_disable) for that and the
14 immediately upstream bridge.
15 Should the immediately upstream bridge also set the
16 pre_enable_upstream_first flag, the bridge upstream of that will be called
17 before either of those which requested pre_enable_upstream_first.
22 - Bridge 2 pre_enable_upstream_first
24 - Bridge 4 pre_enable_upstream_first
25 - Bridge 5 pre_enable_upstream_first
28 Would result in pre_enable's being called as Panel, Bridge 1, Bridge 3,
29 Bridge 2, Bridge 6, Bridge 5, Bridge 4, Encoder.
31 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
33 drivers/gpu/drm/drm_bridge.c | 177 +++++++++++++++++++++++++----------
34 include/drm/drm_bridge.h | 8 ++
35 2 files changed, 137 insertions(+), 48 deletions(-)
37 --- a/drivers/gpu/drm/drm_bridge.c
38 +++ b/drivers/gpu/drm/drm_bridge.c
39 @@ -463,20 +463,15 @@ EXPORT_SYMBOL(drm_bridge_chain_disable);
40 * encoder chain, starting from the first bridge to the last. These are called
41 * after completing the encoder's prepare op.
43 + * If a bridge sets @pre_enable_upstream_first, then the @post_disable for that
44 + * bridge will be called before the previous one to reverse the @pre_enable
45 + * calling direction.
47 * Note: the bridge passed should be the one closest to the encoder
49 void drm_bridge_chain_post_disable(struct drm_bridge *bridge)
51 - struct drm_encoder *encoder;
56 - encoder = bridge->encoder;
57 - list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
58 - if (bridge->funcs->post_disable)
59 - bridge->funcs->post_disable(bridge);
61 + drm_atomic_bridge_chain_post_disable(bridge, NULL);
63 EXPORT_SYMBOL(drm_bridge_chain_post_disable);
65 @@ -518,24 +513,14 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_set)
66 * chain, starting from the last bridge to the first. These are called
67 * before calling the encoder's commit op.
69 + * If a bridge sets @pre_enable_upstream_first, then the @pre_enable for the
70 + * previous bridge will be called before @pre_enable of this bridge.
72 * Note: the bridge passed should be the one closest to the encoder
74 void drm_bridge_chain_pre_enable(struct drm_bridge *bridge)
76 - struct drm_encoder *encoder;
77 - struct drm_bridge *iter;
82 - encoder = bridge->encoder;
83 - list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
84 - if (iter->funcs->pre_enable)
85 - iter->funcs->pre_enable(iter);
90 + drm_atomic_bridge_chain_pre_enable(bridge, NULL);
92 EXPORT_SYMBOL(drm_bridge_chain_pre_enable);
94 @@ -607,6 +592,25 @@ void drm_atomic_bridge_chain_disable(str
96 EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
98 +static void drm_atomic_bridge_call_post_disable(struct drm_bridge *bridge,
99 + struct drm_atomic_state *old_state)
101 + if (old_state && bridge->funcs->atomic_post_disable) {
102 + struct drm_bridge_state *old_bridge_state;
105 + drm_atomic_get_old_bridge_state(old_state,
107 + if (WARN_ON(!old_bridge_state))
110 + bridge->funcs->atomic_post_disable(bridge,
112 + } else if (bridge->funcs->post_disable) {
113 + bridge->funcs->post_disable(bridge);
118 * drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges
119 * in the encoder chain
120 @@ -617,6 +621,9 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_di
121 * &drm_bridge_funcs.post_disable) op for all the bridges in the encoder chain,
122 * starting from the first bridge to the last. These are called after completing
123 * &drm_encoder_helper_funcs.atomic_disable
124 + * If a bridge sets @pre_enable_upstream_first, then the @post_disable for that
125 + * bridge will be called before the previous one to reverse the @pre_enable
126 + * calling direction.
128 * Note: the bridge passed should be the one closest to the encoder
130 @@ -624,30 +631,75 @@ void drm_atomic_bridge_chain_post_disabl
131 struct drm_atomic_state *old_state)
133 struct drm_encoder *encoder;
134 + struct drm_bridge *next, *limit;
139 encoder = bridge->encoder;
141 list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
142 - if (bridge->funcs->atomic_post_disable) {
143 - struct drm_bridge_state *old_bridge_state;
147 - drm_atomic_get_old_bridge_state(old_state,
149 - if (WARN_ON(!old_bridge_state))
151 + if (!list_is_last(&bridge->chain_node, &encoder->bridge_chain)) {
152 + next = list_next_entry(bridge, chain_node);
154 - bridge->funcs->atomic_post_disable(bridge,
156 - } else if (bridge->funcs->post_disable) {
157 - bridge->funcs->post_disable(bridge);
158 + if (next->pre_enable_upstream_first) {
159 + /* Downstream bridge had requested that upstream
160 + * was enabled first, so disabled last
164 + /* Find the next bridge that has NOT requested
165 + * upstream to be enabled first / disabled last
167 + list_for_each_entry_from(next, &encoder->bridge_chain,
169 + if (next->pre_enable_upstream_first) {
170 + next = list_prev_entry(next, chain_node);
176 + /* Call these bridges in reverse order */
177 + list_for_each_entry_from_reverse(next, &encoder->bridge_chain,
179 + if (next == bridge)
182 + drm_atomic_bridge_call_post_disable(next,
188 + drm_atomic_bridge_call_post_disable(bridge, old_state);
194 EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
196 +static void drm_atomic_bridge_call_pre_enable(struct drm_bridge *bridge,
197 + struct drm_atomic_state *old_state)
199 + if (old_state && bridge->funcs->atomic_pre_enable) {
200 + struct drm_bridge_state *old_bridge_state;
203 + drm_atomic_get_old_bridge_state(old_state,
205 + if (WARN_ON(!old_bridge_state))
208 + bridge->funcs->atomic_pre_enable(bridge, old_bridge_state);
209 + } else if (bridge->funcs->pre_enable) {
210 + bridge->funcs->pre_enable(bridge);
215 * drm_atomic_bridge_chain_pre_enable - prepares for enabling all bridges in
217 @@ -659,33 +711,62 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_po
218 * starting from the last bridge to the first. These are called before calling
219 * &drm_encoder_helper_funcs.atomic_enable
221 + * If a bridge sets @pre_enable_upstream_first, then the pre_enable for the
222 + * upstream bridge will be called before pre_enable of this bridge.
224 * Note: the bridge passed should be the one closest to the encoder
226 void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
227 struct drm_atomic_state *old_state)
229 struct drm_encoder *encoder;
230 - struct drm_bridge *iter;
231 + struct drm_bridge *iter, *next, *limit;
236 encoder = bridge->encoder;
237 - list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
238 - if (iter->funcs->atomic_pre_enable) {
239 - struct drm_bridge_state *old_bridge_state;
242 - drm_atomic_get_old_bridge_state(old_state,
244 - if (WARN_ON(!old_bridge_state))
246 + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
247 + if (iter->pre_enable_upstream_first) {
250 + list_for_each_entry_from_reverse(next,
251 + &encoder->bridge_chain,
253 + if (next == bridge)
256 + if (!next->pre_enable_upstream_first) {
257 + /* Found first bridge that does NOT
258 + * request upstream to be enabled first
260 + limit = list_prev_entry(next, chain_node);
265 + list_for_each_entry_from(next, &encoder->bridge_chain, chain_node) {
266 + /* Call requested upstream bridge pre_enable
270 + /* At the first bridgge to request upstream
271 + * bridges called first.
275 - iter->funcs->atomic_pre_enable(iter, old_bridge_state);
276 - } else if (iter->funcs->pre_enable) {
277 - iter->funcs->pre_enable(iter);
278 + drm_atomic_bridge_call_pre_enable(next, old_state);
282 + drm_atomic_bridge_call_pre_enable(iter, old_state);
284 + if (iter->pre_enable_upstream_first)
285 + /* Jump all bridges that we have already pre_enabled
292 --- a/include/drm/drm_bridge.h
293 +++ b/include/drm/drm_bridge.h
294 @@ -762,6 +762,14 @@ struct drm_bridge {
296 bool interlace_allowed;
298 + * @pre_enable_upstream_first: The bridge requires that the upstream
299 + * bridge @pre_enable function is called before its @pre_enable,
300 + * and conversely for post_disable. This is most frequently a
301 + * requirement for DSI devices which need the host to be initialised
302 + * before the peripheral.
304 + bool pre_enable_upstream_first;
306 * @ddc: Associated I2C adapter for DDC access, if any.
308 struct i2c_adapter *ddc;