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