This source file includes following definitions.
- DECLARE_EWMA
- drm_self_refresh_helper_entry_work
- drm_self_refresh_helper_update_avg_times
- drm_self_refresh_helper_alter_state
- drm_self_refresh_helper_init
- drm_self_refresh_helper_cleanup
1
2
3
4
5
6
7
8 #include <linux/average.h>
9 #include <linux/bitops.h>
10 #include <linux/slab.h>
11 #include <linux/workqueue.h>
12
13 #include <drm/drm_atomic.h>
14 #include <drm/drm_atomic_helper.h>
15 #include <drm/drm_connector.h>
16 #include <drm/drm_crtc.h>
17 #include <drm/drm_device.h>
18 #include <drm/drm_mode_config.h>
19 #include <drm/drm_modeset_lock.h>
20 #include <drm/drm_print.h>
21 #include <drm/drm_self_refresh_helper.h>
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 #define SELF_REFRESH_AVG_SEED_MS 200
55
56 DECLARE_EWMA(psr_time, 4, 4)
57
58 struct drm_self_refresh_data {
59 struct drm_crtc *crtc;
60 struct delayed_work entry_work;
61
62 struct mutex avg_mutex;
63 struct ewma_psr_time entry_avg_ms;
64 struct ewma_psr_time exit_avg_ms;
65 };
66
67 static void drm_self_refresh_helper_entry_work(struct work_struct *work)
68 {
69 struct drm_self_refresh_data *sr_data = container_of(
70 to_delayed_work(work),
71 struct drm_self_refresh_data, entry_work);
72 struct drm_crtc *crtc = sr_data->crtc;
73 struct drm_device *dev = crtc->dev;
74 struct drm_modeset_acquire_ctx ctx;
75 struct drm_atomic_state *state;
76 struct drm_connector *conn;
77 struct drm_connector_state *conn_state;
78 struct drm_crtc_state *crtc_state;
79 int i, ret = 0;
80
81 drm_modeset_acquire_init(&ctx, 0);
82
83 state = drm_atomic_state_alloc(dev);
84 if (!state) {
85 ret = -ENOMEM;
86 goto out_drop_locks;
87 }
88
89 retry:
90 state->acquire_ctx = &ctx;
91
92 crtc_state = drm_atomic_get_crtc_state(state, crtc);
93 if (IS_ERR(crtc_state)) {
94 ret = PTR_ERR(crtc_state);
95 goto out;
96 }
97
98 if (!crtc_state->enable)
99 goto out;
100
101 ret = drm_atomic_add_affected_connectors(state, crtc);
102 if (ret)
103 goto out;
104
105 for_each_new_connector_in_state(state, conn, conn_state, i) {
106 if (!conn_state->self_refresh_aware)
107 goto out;
108 }
109
110 crtc_state->active = false;
111 crtc_state->self_refresh_active = true;
112
113 ret = drm_atomic_commit(state);
114 if (ret)
115 goto out;
116
117 out:
118 if (ret == -EDEADLK) {
119 drm_atomic_state_clear(state);
120 ret = drm_modeset_backoff(&ctx);
121 if (!ret)
122 goto retry;
123 }
124
125 drm_atomic_state_put(state);
126
127 out_drop_locks:
128 drm_modeset_drop_locks(&ctx);
129 drm_modeset_acquire_fini(&ctx);
130 }
131
132
133
134
135
136
137
138
139
140
141
142
143
144 void
145 drm_self_refresh_helper_update_avg_times(struct drm_atomic_state *state,
146 unsigned int commit_time_ms,
147 unsigned int new_self_refresh_mask)
148 {
149 struct drm_crtc *crtc;
150 struct drm_crtc_state *old_crtc_state;
151 int i;
152
153 for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
154 bool new_self_refresh_active = new_self_refresh_mask & BIT(i);
155 struct drm_self_refresh_data *sr_data = crtc->self_refresh_data;
156 struct ewma_psr_time *time;
157
158 if (old_crtc_state->self_refresh_active ==
159 new_self_refresh_active)
160 continue;
161
162 if (new_self_refresh_active)
163 time = &sr_data->entry_avg_ms;
164 else
165 time = &sr_data->exit_avg_ms;
166
167 mutex_lock(&sr_data->avg_mutex);
168 ewma_psr_time_add(time, commit_time_ms);
169 mutex_unlock(&sr_data->avg_mutex);
170 }
171 }
172 EXPORT_SYMBOL(drm_self_refresh_helper_update_avg_times);
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187 void drm_self_refresh_helper_alter_state(struct drm_atomic_state *state)
188 {
189 struct drm_crtc *crtc;
190 struct drm_crtc_state *crtc_state;
191 int i;
192
193 if (state->async_update || !state->allow_modeset) {
194 for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
195 if (crtc_state->self_refresh_active) {
196 state->async_update = false;
197 state->allow_modeset = true;
198 break;
199 }
200 }
201 }
202
203 for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
204 struct drm_self_refresh_data *sr_data;
205 unsigned int delay;
206
207
208 if (crtc_state->self_refresh_active)
209 continue;
210
211 sr_data = crtc->self_refresh_data;
212 if (!sr_data)
213 continue;
214
215 mutex_lock(&sr_data->avg_mutex);
216 delay = (ewma_psr_time_read(&sr_data->entry_avg_ms) +
217 ewma_psr_time_read(&sr_data->exit_avg_ms)) * 2;
218 mutex_unlock(&sr_data->avg_mutex);
219
220 mod_delayed_work(system_wq, &sr_data->entry_work,
221 msecs_to_jiffies(delay));
222 }
223 }
224 EXPORT_SYMBOL(drm_self_refresh_helper_alter_state);
225
226
227
228
229
230
231
232 int drm_self_refresh_helper_init(struct drm_crtc *crtc)
233 {
234 struct drm_self_refresh_data *sr_data = crtc->self_refresh_data;
235
236
237 if (WARN_ON(sr_data))
238 return -EINVAL;
239
240 sr_data = kzalloc(sizeof(*sr_data), GFP_KERNEL);
241 if (!sr_data)
242 return -ENOMEM;
243
244 INIT_DELAYED_WORK(&sr_data->entry_work,
245 drm_self_refresh_helper_entry_work);
246 sr_data->crtc = crtc;
247 mutex_init(&sr_data->avg_mutex);
248 ewma_psr_time_init(&sr_data->entry_avg_ms);
249 ewma_psr_time_init(&sr_data->exit_avg_ms);
250
251
252
253
254
255
256 ewma_psr_time_add(&sr_data->entry_avg_ms, SELF_REFRESH_AVG_SEED_MS);
257 ewma_psr_time_add(&sr_data->exit_avg_ms, SELF_REFRESH_AVG_SEED_MS);
258
259 crtc->self_refresh_data = sr_data;
260 return 0;
261 }
262 EXPORT_SYMBOL(drm_self_refresh_helper_init);
263
264
265
266
267
268 void drm_self_refresh_helper_cleanup(struct drm_crtc *crtc)
269 {
270 struct drm_self_refresh_data *sr_data = crtc->self_refresh_data;
271
272
273 if (!sr_data)
274 return;
275
276 crtc->self_refresh_data = NULL;
277
278 cancel_delayed_work_sync(&sr_data->entry_work);
279 kfree(sr_data);
280 }
281 EXPORT_SYMBOL(drm_self_refresh_helper_cleanup);