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