1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include <linux/list.h>
27#include <drm/drmP.h>
28#include <drm/drm_plane_helper.h>
29#include <drm/drm_rect.h>
30#include <drm/drm_atomic.h>
31#include <drm/drm_crtc_helper.h>
32#include <drm/drm_encoder.h>
33#include <drm/drm_atomic_helper.h>
34
35#define SUBPIXEL_MASK 0xffff
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72static int get_connectors_for_crtc(struct drm_crtc *crtc,
73 struct drm_connector **connector_list,
74 int num_connectors)
75{
76 struct drm_device *dev = crtc->dev;
77 struct drm_connector *connector;
78 struct drm_connector_list_iter conn_iter;
79 int count = 0;
80
81
82
83
84
85
86 WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
87
88 drm_connector_list_iter_get(dev, &conn_iter);
89 drm_for_each_connector_iter(connector, &conn_iter) {
90 if (connector->encoder && connector->encoder->crtc == crtc) {
91 if (connector_list != NULL && count < num_connectors)
92 *(connector_list++) = connector;
93
94 count++;
95 }
96 }
97 drm_connector_list_iter_put(&conn_iter);
98
99 return count;
100}
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123int drm_plane_helper_check_state(struct drm_plane_state *state,
124 const struct drm_rect *clip,
125 int min_scale,
126 int max_scale,
127 bool can_position,
128 bool can_update_disabled)
129{
130 struct drm_crtc *crtc = state->crtc;
131 struct drm_framebuffer *fb = state->fb;
132 struct drm_rect *src = &state->src;
133 struct drm_rect *dst = &state->dst;
134 unsigned int rotation = state->rotation;
135 int hscale, vscale;
136
137 *src = drm_plane_state_src(state);
138 *dst = drm_plane_state_dest(state);
139
140 if (!fb) {
141 state->visible = false;
142 return 0;
143 }
144
145
146 if (WARN_ON(!crtc)) {
147 state->visible = false;
148 return 0;
149 }
150
151 if (!crtc->enabled && !can_update_disabled) {
152 DRM_DEBUG_KMS("Cannot update plane of a disabled CRTC.\n");
153 return -EINVAL;
154 }
155
156 drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation);
157
158
159 hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
160 vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
161 if (hscale < 0 || vscale < 0) {
162 DRM_DEBUG_KMS("Invalid scaling of plane\n");
163 drm_rect_debug_print("src: ", &state->src, true);
164 drm_rect_debug_print("dst: ", &state->dst, false);
165 return -ERANGE;
166 }
167
168 state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale);
169
170 drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation);
171
172 if (!state->visible)
173
174
175
176
177
178
179
180 return 0;
181
182 if (!can_position && !drm_rect_equals(dst, clip)) {
183 DRM_DEBUG_KMS("Plane must cover entire CRTC\n");
184 drm_rect_debug_print("dst: ", dst, false);
185 drm_rect_debug_print("clip: ", clip, false);
186 return -EINVAL;
187 }
188
189 return 0;
190}
191EXPORT_SYMBOL(drm_plane_helper_check_state);
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220int drm_plane_helper_check_update(struct drm_plane *plane,
221 struct drm_crtc *crtc,
222 struct drm_framebuffer *fb,
223 struct drm_rect *src,
224 struct drm_rect *dst,
225 const struct drm_rect *clip,
226 unsigned int rotation,
227 int min_scale,
228 int max_scale,
229 bool can_position,
230 bool can_update_disabled,
231 bool *visible)
232{
233 struct drm_plane_state state = {
234 .plane = plane,
235 .crtc = crtc,
236 .fb = fb,
237 .src_x = src->x1,
238 .src_y = src->y1,
239 .src_w = drm_rect_width(src),
240 .src_h = drm_rect_height(src),
241 .crtc_x = dst->x1,
242 .crtc_y = dst->y1,
243 .crtc_w = drm_rect_width(dst),
244 .crtc_h = drm_rect_height(dst),
245 .rotation = rotation,
246 .visible = *visible,
247 };
248 int ret;
249
250 ret = drm_plane_helper_check_state(&state, clip,
251 min_scale, max_scale,
252 can_position,
253 can_update_disabled);
254 if (ret)
255 return ret;
256
257 *src = state.src;
258 *dst = state.dst;
259 *visible = state.visible;
260
261 return 0;
262}
263EXPORT_SYMBOL(drm_plane_helper_check_update);
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
302 struct drm_framebuffer *fb,
303 int crtc_x, int crtc_y,
304 unsigned int crtc_w, unsigned int crtc_h,
305 uint32_t src_x, uint32_t src_y,
306 uint32_t src_w, uint32_t src_h)
307{
308 struct drm_mode_set set = {
309 .crtc = crtc,
310 .fb = fb,
311 .mode = &crtc->mode,
312 .x = src_x >> 16,
313 .y = src_y >> 16,
314 };
315 struct drm_rect src = {
316 .x1 = src_x,
317 .y1 = src_y,
318 .x2 = src_x + src_w,
319 .y2 = src_y + src_h,
320 };
321 struct drm_rect dest = {
322 .x1 = crtc_x,
323 .y1 = crtc_y,
324 .x2 = crtc_x + crtc_w,
325 .y2 = crtc_y + crtc_h,
326 };
327 const struct drm_rect clip = {
328 .x2 = crtc->mode.hdisplay,
329 .y2 = crtc->mode.vdisplay,
330 };
331 struct drm_connector **connector_list;
332 int num_connectors, ret;
333 bool visible;
334
335 ret = drm_plane_helper_check_update(plane, crtc, fb,
336 &src, &dest, &clip,
337 DRM_ROTATE_0,
338 DRM_PLANE_HELPER_NO_SCALING,
339 DRM_PLANE_HELPER_NO_SCALING,
340 false, false, &visible);
341 if (ret)
342 return ret;
343
344 if (!visible)
345
346
347
348
349
350 return plane->funcs->disable_plane(plane);
351
352
353 num_connectors = get_connectors_for_crtc(crtc, NULL, 0);
354 BUG_ON(num_connectors == 0);
355 connector_list = kzalloc(num_connectors * sizeof(*connector_list),
356 GFP_KERNEL);
357 if (!connector_list)
358 return -ENOMEM;
359 get_connectors_for_crtc(crtc, connector_list, num_connectors);
360
361 set.connectors = connector_list;
362 set.num_connectors = num_connectors;
363
364
365
366
367
368
369
370
371
372 ret = crtc->funcs->set_config(&set);
373
374 kfree(connector_list);
375 return ret;
376}
377EXPORT_SYMBOL(drm_primary_helper_update);
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399int drm_primary_helper_disable(struct drm_plane *plane)
400{
401 return -EINVAL;
402}
403EXPORT_SYMBOL(drm_primary_helper_disable);
404
405
406
407
408
409
410
411
412
413void drm_primary_helper_destroy(struct drm_plane *plane)
414{
415 drm_plane_cleanup(plane);
416 kfree(plane);
417}
418EXPORT_SYMBOL(drm_primary_helper_destroy);
419
420const struct drm_plane_funcs drm_primary_helper_funcs = {
421 .update_plane = drm_primary_helper_update,
422 .disable_plane = drm_primary_helper_disable,
423 .destroy = drm_primary_helper_destroy,
424};
425EXPORT_SYMBOL(drm_primary_helper_funcs);
426
427int drm_plane_helper_commit(struct drm_plane *plane,
428 struct drm_plane_state *plane_state,
429 struct drm_framebuffer *old_fb)
430{
431 const struct drm_plane_helper_funcs *plane_funcs;
432 struct drm_crtc *crtc[2];
433 const struct drm_crtc_helper_funcs *crtc_funcs[2];
434 int i, ret = 0;
435
436 plane_funcs = plane->helper_private;
437
438
439
440
441 crtc[0] = plane->crtc;
442 crtc[1] = crtc[0] != plane_state->crtc ? plane_state->crtc : NULL;
443
444 for (i = 0; i < 2; i++)
445 crtc_funcs[i] = crtc[i] ? crtc[i]->helper_private : NULL;
446
447 if (plane_funcs->atomic_check) {
448 ret = plane_funcs->atomic_check(plane, plane_state);
449 if (ret)
450 goto out;
451 }
452
453 if (plane_funcs->prepare_fb && plane_state->fb &&
454 plane_state->fb != old_fb) {
455 ret = plane_funcs->prepare_fb(plane,
456 plane_state);
457 if (ret)
458 goto out;
459 }
460
461
462 swap(plane->state, plane_state);
463
464 for (i = 0; i < 2; i++) {
465 if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin)
466 crtc_funcs[i]->atomic_begin(crtc[i], crtc[i]->state);
467 }
468
469
470
471
472
473 if (drm_atomic_plane_disabling(plane, plane_state) &&
474 plane_funcs->atomic_disable)
475 plane_funcs->atomic_disable(plane, plane_state);
476 else
477 plane_funcs->atomic_update(plane, plane_state);
478
479 for (i = 0; i < 2; i++) {
480 if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush)
481 crtc_funcs[i]->atomic_flush(crtc[i], crtc[i]->state);
482 }
483
484
485
486
487
488 if (plane->state->fb == old_fb)
489 goto out;
490
491 for (i = 0; i < 2; i++) {
492 if (!crtc[i])
493 continue;
494
495 if (crtc[i]->cursor == plane)
496 continue;
497
498
499 ret = drm_crtc_vblank_get(crtc[i]);
500 if (ret == 0) {
501 drm_crtc_wait_one_vblank(crtc[i]);
502 drm_crtc_vblank_put(crtc[i]);
503 }
504
505 ret = 0;
506 }
507
508 if (plane_funcs->cleanup_fb)
509 plane_funcs->cleanup_fb(plane, plane_state);
510out:
511 if (plane_state) {
512 if (plane->funcs->atomic_destroy_state)
513 plane->funcs->atomic_destroy_state(plane, plane_state);
514 else
515 drm_atomic_helper_plane_destroy_state(plane, plane_state);
516 }
517
518 return ret;
519}
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
545 struct drm_framebuffer *fb,
546 int crtc_x, int crtc_y,
547 unsigned int crtc_w, unsigned int crtc_h,
548 uint32_t src_x, uint32_t src_y,
549 uint32_t src_w, uint32_t src_h)
550{
551 struct drm_plane_state *plane_state;
552
553 if (plane->funcs->atomic_duplicate_state)
554 plane_state = plane->funcs->atomic_duplicate_state(plane);
555 else {
556 if (!plane->state)
557 drm_atomic_helper_plane_reset(plane);
558
559 plane_state = drm_atomic_helper_plane_duplicate_state(plane);
560 }
561 if (!plane_state)
562 return -ENOMEM;
563 plane_state->plane = plane;
564
565 plane_state->crtc = crtc;
566 drm_atomic_set_fb_for_plane(plane_state, fb);
567 plane_state->crtc_x = crtc_x;
568 plane_state->crtc_y = crtc_y;
569 plane_state->crtc_h = crtc_h;
570 plane_state->crtc_w = crtc_w;
571 plane_state->src_x = src_x;
572 plane_state->src_y = src_y;
573 plane_state->src_h = src_h;
574 plane_state->src_w = src_w;
575
576 return drm_plane_helper_commit(plane, plane_state, plane->fb);
577}
578EXPORT_SYMBOL(drm_plane_helper_update);
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593int drm_plane_helper_disable(struct drm_plane *plane)
594{
595 struct drm_plane_state *plane_state;
596
597
598
599 if (!plane->crtc)
600 return 0;
601
602 if (plane->funcs->atomic_duplicate_state)
603 plane_state = plane->funcs->atomic_duplicate_state(plane);
604 else {
605 if (!plane->state)
606 drm_atomic_helper_plane_reset(plane);
607
608 plane_state = drm_atomic_helper_plane_duplicate_state(plane);
609 }
610 if (!plane_state)
611 return -ENOMEM;
612 plane_state->plane = plane;
613
614 plane_state->crtc = NULL;
615 drm_atomic_set_fb_for_plane(plane_state, NULL);
616
617 return drm_plane_helper_commit(plane, plane_state, plane->fb);
618}
619EXPORT_SYMBOL(drm_plane_helper_disable);
620