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