bab4ed9b90727f5dea46e3978627d8ee20f5575a
[openwrt/staging/robimarko.git] /
1 From 5365030a003a6cb0c336202256341e4bc9d65d52 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
6
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.
11
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.
18
19 eg:
20 - Panel
21 - Bridge 1
22 - Bridge 2 pre_enable_upstream_first
23 - Bridge 3
24 - Bridge 4 pre_enable_upstream_first
25 - Bridge 5 pre_enable_upstream_first
26 - Bridge 6
27 - Encoder
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.
30
31 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
32 ---
33 drivers/gpu/drm/drm_bridge.c | 177 +++++++++++++++++++++++++----------
34 include/drm/drm_bridge.h | 8 ++
35 2 files changed, 137 insertions(+), 48 deletions(-)
36
37 --- a/drivers/gpu/drm/drm_bridge.c
38 +++ b/drivers/gpu/drm/drm_bridge.c
39 @@ -547,20 +547,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.
42 *
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.
46 + *
47 * Note: the bridge passed should be the one closest to the encoder
48 */
49 void drm_bridge_chain_post_disable(struct drm_bridge *bridge)
50 {
51 - struct drm_encoder *encoder;
52 -
53 - if (!bridge)
54 - return;
55 -
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);
60 - }
61 + drm_atomic_bridge_chain_post_disable(bridge, NULL);
62 }
63 EXPORT_SYMBOL(drm_bridge_chain_post_disable);
64
65 @@ -602,24 +597,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.
68 *
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.
71 + *
72 * Note: the bridge passed should be the one closest to the encoder
73 */
74 void drm_bridge_chain_pre_enable(struct drm_bridge *bridge)
75 {
76 - struct drm_encoder *encoder;
77 - struct drm_bridge *iter;
78 -
79 - if (!bridge)
80 - return;
81 -
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);
86 -
87 - if (iter == bridge)
88 - break;
89 - }
90 + drm_atomic_bridge_chain_pre_enable(bridge, NULL);
91 }
92 EXPORT_SYMBOL(drm_bridge_chain_pre_enable);
93
94 @@ -691,6 +676,25 @@ void drm_atomic_bridge_chain_disable(str
95 }
96 EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
97
98 +static void drm_atomic_bridge_call_post_disable(struct drm_bridge *bridge,
99 + struct drm_atomic_state *old_state)
100 +{
101 + if (old_state && bridge->funcs->atomic_post_disable) {
102 + struct drm_bridge_state *old_bridge_state;
103 +
104 + old_bridge_state =
105 + drm_atomic_get_old_bridge_state(old_state,
106 + bridge);
107 + if (WARN_ON(!old_bridge_state))
108 + return;
109 +
110 + bridge->funcs->atomic_post_disable(bridge,
111 + old_bridge_state);
112 + } else if (bridge->funcs->post_disable) {
113 + bridge->funcs->post_disable(bridge);
114 + }
115 +}
116 +
117 /**
118 * drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges
119 * in the encoder chain
120 @@ -701,6 +705,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.
127 *
128 * Note: the bridge passed should be the one closest to the encoder
129 */
130 @@ -708,30 +715,75 @@ void drm_atomic_bridge_chain_post_disabl
131 struct drm_atomic_state *old_state)
132 {
133 struct drm_encoder *encoder;
134 + struct drm_bridge *next, *limit;
135
136 if (!bridge)
137 return;
138
139 encoder = bridge->encoder;
140 +
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;
144 + limit = NULL;
145
146 - old_bridge_state =
147 - drm_atomic_get_old_bridge_state(old_state,
148 - bridge);
149 - if (WARN_ON(!old_bridge_state))
150 - return;
151 + if (!list_is_last(&bridge->chain_node, &encoder->bridge_chain)) {
152 + next = list_next_entry(bridge, chain_node);
153
154 - bridge->funcs->atomic_post_disable(bridge,
155 - old_bridge_state);
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
161 + */
162 + limit = next;
163 +
164 + /* Find the next bridge that has NOT requested
165 + * upstream to be enabled first / disabled last
166 + */
167 + list_for_each_entry_from(next, &encoder->bridge_chain,
168 + chain_node) {
169 + if (next->pre_enable_upstream_first) {
170 + next = list_prev_entry(next, chain_node);
171 + limit = next;
172 + break;
173 + }
174 + }
175 +
176 + /* Call these bridges in reverse order */
177 + list_for_each_entry_from_reverse(next, &encoder->bridge_chain,
178 + chain_node) {
179 + if (next == bridge)
180 + break;
181 +
182 + drm_atomic_bridge_call_post_disable(next,
183 + old_state);
184 + }
185 + }
186 }
187 +
188 + drm_atomic_bridge_call_post_disable(bridge, old_state);
189 +
190 + if (limit)
191 + bridge = limit;
192 }
193 }
194 EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
195
196 +static void drm_atomic_bridge_call_pre_enable(struct drm_bridge *bridge,
197 + struct drm_atomic_state *old_state)
198 +{
199 + if (old_state && bridge->funcs->atomic_pre_enable) {
200 + struct drm_bridge_state *old_bridge_state;
201 +
202 + old_bridge_state =
203 + drm_atomic_get_old_bridge_state(old_state,
204 + bridge);
205 + if (WARN_ON(!old_bridge_state))
206 + return;
207 +
208 + bridge->funcs->atomic_pre_enable(bridge, old_bridge_state);
209 + } else if (bridge->funcs->pre_enable) {
210 + bridge->funcs->pre_enable(bridge);
211 + }
212 +}
213 +
214 /**
215 * drm_atomic_bridge_chain_pre_enable - prepares for enabling all bridges in
216 * the encoder chain
217 @@ -743,33 +795,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
220 *
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.
223 + *
224 * Note: the bridge passed should be the one closest to the encoder
225 */
226 void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
227 struct drm_atomic_state *old_state)
228 {
229 struct drm_encoder *encoder;
230 - struct drm_bridge *iter;
231 + struct drm_bridge *iter, *next, *limit;
232
233 if (!bridge)
234 return;
235
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;
240
241 - old_bridge_state =
242 - drm_atomic_get_old_bridge_state(old_state,
243 - iter);
244 - if (WARN_ON(!old_bridge_state))
245 - return;
246 + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
247 + if (iter->pre_enable_upstream_first) {
248 + next = iter;
249 + limit = bridge;
250 + list_for_each_entry_from_reverse(next,
251 + &encoder->bridge_chain,
252 + chain_node) {
253 + if (next == bridge)
254 + break;
255 +
256 + if (!next->pre_enable_upstream_first) {
257 + /* Found first bridge that does NOT
258 + * request upstream to be enabled first
259 + */
260 + limit = list_prev_entry(next, chain_node);
261 + break;
262 + }
263 + }
264 +
265 + list_for_each_entry_from(next, &encoder->bridge_chain, chain_node) {
266 + /* Call requested upstream bridge pre_enable
267 + * in order.
268 + */
269 + if (next == iter)
270 + /* At the first bridgge to request upstream
271 + * bridges called first.
272 + */
273 + break;
274
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);
279 + }
280 }
281
282 + drm_atomic_bridge_call_pre_enable(iter, old_state);
283 +
284 + if (iter->pre_enable_upstream_first)
285 + /* Jump all bridges that we have already pre_enabled
286 + */
287 + iter = limit;
288 +
289 if (iter == bridge)
290 break;
291 }
292 --- a/include/drm/drm_bridge.h
293 +++ b/include/drm/drm_bridge.h
294 @@ -769,6 +769,14 @@ struct drm_bridge {
295 */
296 bool interlace_allowed;
297 /**
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.
303 + */
304 + bool pre_enable_upstream_first;
305 + /**
306 * @ddc: Associated I2C adapter for DDC access, if any.
307 */
308 struct i2c_adapter *ddc;