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