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_begin(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_end(&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
301
302int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
303 struct drm_framebuffer *fb,
304 int crtc_x, int crtc_y,
305 unsigned int crtc_w, unsigned int crtc_h,
306 uint32_t src_x, uint32_t src_y,
307 uint32_t src_w, uint32_t src_h,
308 struct drm_modeset_acquire_ctx *ctx)
309{
310 struct drm_mode_set set = {
311 .crtc = crtc,
312 .fb = fb,
313 .mode = &crtc->mode,
314 .x = src_x >> 16,
315 .y = src_y >> 16,
316 };
317 struct drm_rect src = {
318 .x1 = src_x,
319 .y1 = src_y,
320 .x2 = src_x + src_w,
321 .y2 = src_y + src_h,
322 };
323 struct drm_rect dest = {
324 .x1 = crtc_x,
325 .y1 = crtc_y,
326 .x2 = crtc_x + crtc_w,
327 .y2 = crtc_y + crtc_h,
328 };
329 const struct drm_rect clip = {
330 .x2 = crtc->mode.hdisplay,
331 .y2 = crtc->mode.vdisplay,
332 };
333 struct drm_connector **connector_list;
334 int num_connectors, ret;
335 bool visible;
336
337 ret = drm_plane_helper_check_update(plane, crtc, fb,
338 &src, &dest, &clip,
339 DRM_MODE_ROTATE_0,
340 DRM_PLANE_HELPER_NO_SCALING,
341 DRM_PLANE_HELPER_NO_SCALING,
342 false, false, &visible);
343 if (ret)
344 return ret;
345
346 if (!visible)
347
348
349
350
351
352 return plane->funcs->disable_plane(plane, ctx);
353
354
355 num_connectors = get_connectors_for_crtc(crtc, NULL, 0);
356 BUG_ON(num_connectors == 0);
357 connector_list = kzalloc(num_connectors * sizeof(*connector_list),
358 GFP_KERNEL);
359 if (!connector_list)
360 return -ENOMEM;
361 get_connectors_for_crtc(crtc, connector_list, num_connectors);
362
363 set.connectors = connector_list;
364 set.num_connectors = num_connectors;
365
366
367
368
369
370
371
372
373
374 ret = crtc->funcs->set_config(&set, ctx);
375
376 kfree(connector_list);
377 return ret;
378}
379EXPORT_SYMBOL(drm_primary_helper_update);
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402int drm_primary_helper_disable(struct drm_plane *plane,
403 struct drm_modeset_acquire_ctx *ctx)
404{
405 return -EINVAL;
406}
407EXPORT_SYMBOL(drm_primary_helper_disable);
408
409
410
411
412
413
414
415
416
417void drm_primary_helper_destroy(struct drm_plane *plane)
418{
419 drm_plane_cleanup(plane);
420 kfree(plane);
421}
422EXPORT_SYMBOL(drm_primary_helper_destroy);
423
424const struct drm_plane_funcs drm_primary_helper_funcs = {
425 .update_plane = drm_primary_helper_update,
426 .disable_plane = drm_primary_helper_disable,
427 .destroy = drm_primary_helper_destroy,
428};
429EXPORT_SYMBOL(drm_primary_helper_funcs);
430
431int drm_plane_helper_commit(struct drm_plane *plane,
432 struct drm_plane_state *plane_state,
433 struct drm_framebuffer *old_fb)
434{
435 const struct drm_plane_helper_funcs *plane_funcs;
436 struct drm_crtc *crtc[2];
437 const struct drm_crtc_helper_funcs *crtc_funcs[2];
438 int i, ret = 0;
439
440 plane_funcs = plane->helper_private;
441
442
443
444
445 crtc[0] = plane->crtc;
446 crtc[1] = crtc[0] != plane_state->crtc ? plane_state->crtc : NULL;
447
448 for (i = 0; i < 2; i++)
449 crtc_funcs[i] = crtc[i] ? crtc[i]->helper_private : NULL;
450
451 if (plane_funcs->atomic_check) {
452 ret = plane_funcs->atomic_check(plane, plane_state);
453 if (ret)
454 goto out;
455 }
456
457 if (plane_funcs->prepare_fb && plane_state->fb != old_fb) {
458 ret = plane_funcs->prepare_fb(plane,
459 plane_state);
460 if (ret)
461 goto out;
462 }
463
464
465 swap(plane->state, plane_state);
466
467 for (i = 0; i < 2; i++) {
468 if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin)
469 crtc_funcs[i]->atomic_begin(crtc[i], crtc[i]->state);
470 }
471
472
473
474
475
476 if (drm_atomic_plane_disabling(plane_state, plane->state) &&
477 plane_funcs->atomic_disable)
478 plane_funcs->atomic_disable(plane, plane_state);
479 else
480 plane_funcs->atomic_update(plane, plane_state);
481
482 for (i = 0; i < 2; i++) {
483 if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush)
484 crtc_funcs[i]->atomic_flush(crtc[i], crtc[i]->state);
485 }
486
487
488
489
490
491 if (plane->state->fb == old_fb)
492 goto out;
493
494 for (i = 0; i < 2; i++) {
495 if (!crtc[i])
496 continue;
497
498 if (crtc[i]->cursor == plane)
499 continue;
500
501
502 ret = drm_crtc_vblank_get(crtc[i]);
503 if (ret == 0) {
504 drm_crtc_wait_one_vblank(crtc[i]);
505 drm_crtc_vblank_put(crtc[i]);
506 }
507
508 ret = 0;
509 }
510
511 if (plane_funcs->cleanup_fb)
512 plane_funcs->cleanup_fb(plane, plane_state);
513out:
514 if (plane->funcs->atomic_destroy_state)
515 plane->funcs->atomic_destroy_state(plane, plane_state);
516 else
517 drm_atomic_helper_plane_destroy_state(plane, plane_state);
518
519 return ret;
520}
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
546 struct drm_framebuffer *fb,
547 int crtc_x, int crtc_y,
548 unsigned int crtc_w, unsigned int crtc_h,
549 uint32_t src_x, uint32_t src_y,
550 uint32_t src_w, uint32_t src_h)
551{
552 struct drm_plane_state *plane_state;
553
554 if (plane->funcs->atomic_duplicate_state)
555 plane_state = plane->funcs->atomic_duplicate_state(plane);
556 else {
557 if (!plane->state)
558 drm_atomic_helper_plane_reset(plane);
559
560 plane_state = drm_atomic_helper_plane_duplicate_state(plane);
561 }
562 if (!plane_state)
563 return -ENOMEM;
564 plane_state->plane = plane;
565
566 plane_state->crtc = crtc;
567 drm_atomic_set_fb_for_plane(plane_state, fb);
568 plane_state->crtc_x = crtc_x;
569 plane_state->crtc_y = crtc_y;
570 plane_state->crtc_h = crtc_h;
571 plane_state->crtc_w = crtc_w;
572 plane_state->src_x = src_x;
573 plane_state->src_y = src_y;
574 plane_state->src_h = src_h;
575 plane_state->src_w = src_w;
576
577 return drm_plane_helper_commit(plane, plane_state, plane->fb);
578}
579EXPORT_SYMBOL(drm_plane_helper_update);
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594int drm_plane_helper_disable(struct drm_plane *plane)
595{
596 struct drm_plane_state *plane_state;
597
598
599
600 if (!plane->crtc)
601 return 0;
602
603 if (plane->funcs->atomic_duplicate_state)
604 plane_state = plane->funcs->atomic_duplicate_state(plane);
605 else {
606 if (!plane->state)
607 drm_atomic_helper_plane_reset(plane);
608
609 plane_state = drm_atomic_helper_plane_duplicate_state(plane);
610 }
611 if (!plane_state)
612 return -ENOMEM;
613 plane_state->plane = plane;
614
615 plane_state->crtc = NULL;
616 drm_atomic_set_fb_for_plane(plane_state, NULL);
617
618 return drm_plane_helper_commit(plane, plane_state, plane->fb);
619}
620EXPORT_SYMBOL(drm_plane_helper_disable);
621