1 | /* SPDX-License-Identifier: MIT */ |
2 | /* |
3 | * Copyright © 2019 Intel Corporation |
4 | */ |
5 | |
6 | #ifndef __INTEL_DISPLAY_POWER_H__ |
7 | #define __INTEL_DISPLAY_POWER_H__ |
8 | |
9 | #include <linux/mutex.h> |
10 | #include <linux/workqueue.h> |
11 | |
12 | #include "intel_wakeref.h" |
13 | |
14 | enum aux_ch; |
15 | enum port; |
16 | struct drm_i915_private; |
17 | struct i915_power_well; |
18 | struct intel_encoder; |
19 | struct seq_file; |
20 | |
21 | /* |
22 | * Keep the pipe, transcoder, port (DDI_LANES,DDI_IO,AUX) domain instances |
23 | * consecutive, so that the pipe,transcoder,port -> power domain macros |
24 | * work correctly. |
25 | */ |
26 | enum intel_display_power_domain { |
27 | POWER_DOMAIN_DISPLAY_CORE, |
28 | POWER_DOMAIN_PIPE_A, |
29 | POWER_DOMAIN_PIPE_B, |
30 | POWER_DOMAIN_PIPE_C, |
31 | POWER_DOMAIN_PIPE_D, |
32 | POWER_DOMAIN_PIPE_PANEL_FITTER_A, |
33 | POWER_DOMAIN_PIPE_PANEL_FITTER_B, |
34 | POWER_DOMAIN_PIPE_PANEL_FITTER_C, |
35 | POWER_DOMAIN_PIPE_PANEL_FITTER_D, |
36 | POWER_DOMAIN_TRANSCODER_A, |
37 | POWER_DOMAIN_TRANSCODER_B, |
38 | POWER_DOMAIN_TRANSCODER_C, |
39 | POWER_DOMAIN_TRANSCODER_D, |
40 | POWER_DOMAIN_TRANSCODER_EDP, |
41 | POWER_DOMAIN_TRANSCODER_DSI_A, |
42 | POWER_DOMAIN_TRANSCODER_DSI_C, |
43 | |
44 | /* VDSC/joining for eDP/DSI transcoder (ICL) or pipe A (TGL) */ |
45 | POWER_DOMAIN_TRANSCODER_VDSC_PW2, |
46 | |
47 | POWER_DOMAIN_PORT_DDI_LANES_A, |
48 | POWER_DOMAIN_PORT_DDI_LANES_B, |
49 | POWER_DOMAIN_PORT_DDI_LANES_C, |
50 | POWER_DOMAIN_PORT_DDI_LANES_D, |
51 | POWER_DOMAIN_PORT_DDI_LANES_E, |
52 | POWER_DOMAIN_PORT_DDI_LANES_F, |
53 | |
54 | POWER_DOMAIN_PORT_DDI_LANES_TC1, |
55 | POWER_DOMAIN_PORT_DDI_LANES_TC2, |
56 | POWER_DOMAIN_PORT_DDI_LANES_TC3, |
57 | POWER_DOMAIN_PORT_DDI_LANES_TC4, |
58 | POWER_DOMAIN_PORT_DDI_LANES_TC5, |
59 | POWER_DOMAIN_PORT_DDI_LANES_TC6, |
60 | |
61 | POWER_DOMAIN_PORT_DDI_IO_A, |
62 | POWER_DOMAIN_PORT_DDI_IO_B, |
63 | POWER_DOMAIN_PORT_DDI_IO_C, |
64 | POWER_DOMAIN_PORT_DDI_IO_D, |
65 | POWER_DOMAIN_PORT_DDI_IO_E, |
66 | POWER_DOMAIN_PORT_DDI_IO_F, |
67 | |
68 | POWER_DOMAIN_PORT_DDI_IO_TC1, |
69 | POWER_DOMAIN_PORT_DDI_IO_TC2, |
70 | POWER_DOMAIN_PORT_DDI_IO_TC3, |
71 | POWER_DOMAIN_PORT_DDI_IO_TC4, |
72 | POWER_DOMAIN_PORT_DDI_IO_TC5, |
73 | POWER_DOMAIN_PORT_DDI_IO_TC6, |
74 | |
75 | POWER_DOMAIN_PORT_DSI, |
76 | POWER_DOMAIN_PORT_CRT, |
77 | POWER_DOMAIN_PORT_OTHER, |
78 | POWER_DOMAIN_VGA, |
79 | POWER_DOMAIN_AUDIO_MMIO, |
80 | POWER_DOMAIN_AUDIO_PLAYBACK, |
81 | |
82 | POWER_DOMAIN_AUX_IO_A, |
83 | POWER_DOMAIN_AUX_IO_B, |
84 | POWER_DOMAIN_AUX_IO_C, |
85 | POWER_DOMAIN_AUX_IO_D, |
86 | POWER_DOMAIN_AUX_IO_E, |
87 | POWER_DOMAIN_AUX_IO_F, |
88 | |
89 | POWER_DOMAIN_AUX_A, |
90 | POWER_DOMAIN_AUX_B, |
91 | POWER_DOMAIN_AUX_C, |
92 | POWER_DOMAIN_AUX_D, |
93 | POWER_DOMAIN_AUX_E, |
94 | POWER_DOMAIN_AUX_F, |
95 | |
96 | POWER_DOMAIN_AUX_USBC1, |
97 | POWER_DOMAIN_AUX_USBC2, |
98 | POWER_DOMAIN_AUX_USBC3, |
99 | POWER_DOMAIN_AUX_USBC4, |
100 | POWER_DOMAIN_AUX_USBC5, |
101 | POWER_DOMAIN_AUX_USBC6, |
102 | |
103 | POWER_DOMAIN_AUX_TBT1, |
104 | POWER_DOMAIN_AUX_TBT2, |
105 | POWER_DOMAIN_AUX_TBT3, |
106 | POWER_DOMAIN_AUX_TBT4, |
107 | POWER_DOMAIN_AUX_TBT5, |
108 | POWER_DOMAIN_AUX_TBT6, |
109 | |
110 | POWER_DOMAIN_GMBUS, |
111 | POWER_DOMAIN_GT_IRQ, |
112 | POWER_DOMAIN_DC_OFF, |
113 | POWER_DOMAIN_TC_COLD_OFF, |
114 | POWER_DOMAIN_INIT, |
115 | |
116 | POWER_DOMAIN_NUM, |
117 | POWER_DOMAIN_INVALID = POWER_DOMAIN_NUM, |
118 | }; |
119 | |
120 | #define POWER_DOMAIN_PIPE(pipe) ((pipe) + POWER_DOMAIN_PIPE_A) |
121 | #define POWER_DOMAIN_PIPE_PANEL_FITTER(pipe) \ |
122 | ((pipe) + POWER_DOMAIN_PIPE_PANEL_FITTER_A) |
123 | #define POWER_DOMAIN_TRANSCODER(tran) \ |
124 | ((tran) == TRANSCODER_EDP ? POWER_DOMAIN_TRANSCODER_EDP : \ |
125 | (tran) + POWER_DOMAIN_TRANSCODER_A) |
126 | |
127 | struct intel_power_domain_mask { |
128 | DECLARE_BITMAP(bits, POWER_DOMAIN_NUM); |
129 | }; |
130 | |
131 | struct i915_power_domains { |
132 | /* |
133 | * Power wells needed for initialization at driver init and suspend |
134 | * time are on. They are kept on until after the first modeset. |
135 | */ |
136 | bool initializing; |
137 | bool display_core_suspended; |
138 | int power_well_count; |
139 | |
140 | u32 dc_state; |
141 | u32 target_dc_state; |
142 | u32 allowed_dc_mask; |
143 | |
144 | intel_wakeref_t init_wakeref; |
145 | intel_wakeref_t disable_wakeref; |
146 | |
147 | struct mutex lock; |
148 | int domain_use_count[POWER_DOMAIN_NUM]; |
149 | |
150 | struct delayed_work async_put_work; |
151 | intel_wakeref_t async_put_wakeref; |
152 | struct intel_power_domain_mask async_put_domains[2]; |
153 | int async_put_next_delay; |
154 | |
155 | struct i915_power_well *power_wells; |
156 | }; |
157 | |
158 | struct intel_display_power_domain_set { |
159 | struct intel_power_domain_mask mask; |
160 | #ifdef CONFIG_DRM_I915_DEBUG_RUNTIME_PM |
161 | intel_wakeref_t wakerefs[POWER_DOMAIN_NUM]; |
162 | #endif |
163 | }; |
164 | |
165 | #define for_each_power_domain(__domain, __mask) \ |
166 | for ((__domain) = 0; (__domain) < POWER_DOMAIN_NUM; (__domain)++) \ |
167 | for_each_if(test_bit((__domain), (__mask)->bits)) |
168 | |
169 | int intel_power_domains_init(struct drm_i915_private *dev_priv); |
170 | void intel_power_domains_cleanup(struct drm_i915_private *dev_priv); |
171 | void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume); |
172 | void intel_power_domains_driver_remove(struct drm_i915_private *dev_priv); |
173 | void intel_power_domains_enable(struct drm_i915_private *dev_priv); |
174 | void intel_power_domains_disable(struct drm_i915_private *dev_priv); |
175 | void intel_power_domains_suspend(struct drm_i915_private *dev_priv, bool s2idle); |
176 | void intel_power_domains_resume(struct drm_i915_private *dev_priv); |
177 | void intel_power_domains_sanitize_state(struct drm_i915_private *dev_priv); |
178 | |
179 | void intel_display_power_suspend_late(struct drm_i915_private *i915); |
180 | void intel_display_power_resume_early(struct drm_i915_private *i915); |
181 | void intel_display_power_suspend(struct drm_i915_private *i915); |
182 | void intel_display_power_resume(struct drm_i915_private *i915); |
183 | void intel_display_power_set_target_dc_state(struct drm_i915_private *dev_priv, |
184 | u32 state); |
185 | |
186 | const char * |
187 | intel_display_power_domain_str(enum intel_display_power_domain domain); |
188 | |
189 | bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv, |
190 | enum intel_display_power_domain domain); |
191 | bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv, |
192 | enum intel_display_power_domain domain); |
193 | intel_wakeref_t intel_display_power_get(struct drm_i915_private *dev_priv, |
194 | enum intel_display_power_domain domain); |
195 | intel_wakeref_t |
196 | intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv, |
197 | enum intel_display_power_domain domain); |
198 | void __intel_display_power_put_async(struct drm_i915_private *i915, |
199 | enum intel_display_power_domain domain, |
200 | intel_wakeref_t wakeref, |
201 | int delay_ms); |
202 | void intel_display_power_flush_work(struct drm_i915_private *i915); |
203 | #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) |
204 | void intel_display_power_put(struct drm_i915_private *dev_priv, |
205 | enum intel_display_power_domain domain, |
206 | intel_wakeref_t wakeref); |
207 | static inline void |
208 | intel_display_power_put_async(struct drm_i915_private *i915, |
209 | enum intel_display_power_domain domain, |
210 | intel_wakeref_t wakeref) |
211 | { |
212 | __intel_display_power_put_async(i915, domain, wakeref, delay_ms: -1); |
213 | } |
214 | |
215 | static inline void |
216 | intel_display_power_put_async_delay(struct drm_i915_private *i915, |
217 | enum intel_display_power_domain domain, |
218 | intel_wakeref_t wakeref, |
219 | int delay_ms) |
220 | { |
221 | __intel_display_power_put_async(i915, domain, wakeref, delay_ms); |
222 | } |
223 | #else |
224 | void intel_display_power_put_unchecked(struct drm_i915_private *dev_priv, |
225 | enum intel_display_power_domain domain); |
226 | |
227 | static inline void |
228 | intel_display_power_put(struct drm_i915_private *i915, |
229 | enum intel_display_power_domain domain, |
230 | intel_wakeref_t wakeref) |
231 | { |
232 | intel_display_power_put_unchecked(i915, domain); |
233 | } |
234 | |
235 | static inline void |
236 | intel_display_power_put_async(struct drm_i915_private *i915, |
237 | enum intel_display_power_domain domain, |
238 | intel_wakeref_t wakeref) |
239 | { |
240 | __intel_display_power_put_async(i915, domain, -1, -1); |
241 | } |
242 | |
243 | static inline void |
244 | intel_display_power_put_async_delay(struct drm_i915_private *i915, |
245 | enum intel_display_power_domain domain, |
246 | intel_wakeref_t wakeref, |
247 | int delay_ms) |
248 | { |
249 | __intel_display_power_put_async(i915, domain, -1, delay_ms); |
250 | } |
251 | #endif |
252 | |
253 | void |
254 | intel_display_power_get_in_set(struct drm_i915_private *i915, |
255 | struct intel_display_power_domain_set *power_domain_set, |
256 | enum intel_display_power_domain domain); |
257 | |
258 | bool |
259 | intel_display_power_get_in_set_if_enabled(struct drm_i915_private *i915, |
260 | struct intel_display_power_domain_set *power_domain_set, |
261 | enum intel_display_power_domain domain); |
262 | |
263 | void |
264 | intel_display_power_put_mask_in_set(struct drm_i915_private *i915, |
265 | struct intel_display_power_domain_set *power_domain_set, |
266 | struct intel_power_domain_mask *mask); |
267 | |
268 | static inline void |
269 | intel_display_power_put_all_in_set(struct drm_i915_private *i915, |
270 | struct intel_display_power_domain_set *power_domain_set) |
271 | { |
272 | intel_display_power_put_mask_in_set(i915, power_domain_set, mask: &power_domain_set->mask); |
273 | } |
274 | |
275 | void intel_display_power_debug(struct drm_i915_private *i915, struct seq_file *m); |
276 | |
277 | enum intel_display_power_domain |
278 | intel_display_power_ddi_lanes_domain(struct drm_i915_private *i915, enum port port); |
279 | enum intel_display_power_domain |
280 | intel_display_power_ddi_io_domain(struct drm_i915_private *i915, enum port port); |
281 | enum intel_display_power_domain |
282 | intel_display_power_aux_io_domain(struct drm_i915_private *i915, enum aux_ch aux_ch); |
283 | enum intel_display_power_domain |
284 | intel_display_power_legacy_aux_domain(struct drm_i915_private *i915, enum aux_ch aux_ch); |
285 | enum intel_display_power_domain |
286 | intel_display_power_tbt_aux_domain(struct drm_i915_private *i915, enum aux_ch aux_ch); |
287 | |
288 | /* |
289 | * FIXME: We should probably switch this to a 0-based scheme to be consistent |
290 | * with how we now name/number DBUF_CTL instances. |
291 | */ |
292 | enum dbuf_slice { |
293 | DBUF_S1, |
294 | DBUF_S2, |
295 | DBUF_S3, |
296 | DBUF_S4, |
297 | I915_MAX_DBUF_SLICES |
298 | }; |
299 | |
300 | void gen9_dbuf_slices_update(struct drm_i915_private *dev_priv, |
301 | u8 req_slices); |
302 | |
303 | #define with_intel_display_power(i915, domain, wf) \ |
304 | for ((wf) = intel_display_power_get((i915), (domain)); (wf); \ |
305 | intel_display_power_put_async((i915), (domain), (wf)), (wf) = 0) |
306 | |
307 | #define with_intel_display_power_if_enabled(i915, domain, wf) \ |
308 | for ((wf) = intel_display_power_get_if_enabled((i915), (domain)); (wf); \ |
309 | intel_display_power_put_async((i915), (domain), (wf)), (wf) = 0) |
310 | |
311 | #endif /* __INTEL_DISPLAY_POWER_H__ */ |
312 | |