1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <drm/drmP.h>
19#include <drm/drm_crtc.h>
20#include <drm/drm_fb_cma_helper.h>
21#include <drm/drm_gem_cma_helper.h>
22
23#include <linux/device.h>
24#include <linux/dmaengine.h>
25#include <linux/dma/xilinx_dma.h>
26#include <linux/dma/xilinx_frmbuf.h>
27#include <linux/of_dma.h>
28#include <linux/platform_device.h>
29
30#include "xilinx_drm_dp_sub.h"
31#include "xilinx_drm_drv.h"
32#include "xilinx_drm_fb.h"
33#include "xilinx_drm_plane.h"
34
35#include "xilinx_cresample.h"
36#include "xilinx_osd.h"
37#include "xilinx_rgb2yuv.h"
38
39#define MAX_NUM_SUB_PLANES 4
40
41
42
43
44
45
46
47
48
49struct xilinx_drm_plane_dma {
50 struct dma_chan *chan;
51 struct dma_interleaved_template xt;
52 struct data_chunk sgl[1];
53 bool is_active;
54};
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75struct xilinx_drm_plane {
76 struct drm_plane base;
77 int id;
78 int dpms;
79 unsigned int zpos;
80 unsigned int prio;
81 unsigned int alpha;
82 unsigned int alpha_enable;
83 bool primary;
84 u32 format;
85 struct xilinx_drm_plane_dma dma[MAX_NUM_SUB_PLANES];
86 struct xilinx_rgb2yuv *rgb2yuv;
87 struct xilinx_cresample *cresample;
88 struct xilinx_osd_layer *osd_layer;
89 struct xilinx_drm_dp_sub_layer *dp_layer;
90 struct xilinx_drm_plane_manager *manager;
91};
92
93#define MAX_PLANES 8
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111struct xilinx_drm_plane_manager {
112 struct drm_device *drm;
113 struct device_node *node;
114 struct xilinx_osd *osd;
115 struct xilinx_drm_dp_sub *dp_sub;
116 int num_planes;
117 u32 format;
118 int max_width;
119 struct drm_property *zpos_prop;
120 struct drm_property *alpha_prop;
121 struct drm_property *alpha_enable_prop;
122 unsigned int default_alpha;
123 struct xilinx_drm_plane *planes[MAX_PLANES];
124};
125
126#define to_xilinx_plane(x) container_of(x, struct xilinx_drm_plane, base)
127
128void xilinx_drm_plane_commit(struct drm_plane *base_plane)
129{
130 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
131 struct dma_async_tx_descriptor *desc;
132 enum dma_ctrl_flags flags;
133 unsigned int i;
134
135
136 xilinx_xdma_drm_config(plane->dma[0].chan, plane->format);
137
138 DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
139
140 for (i = 0; i < MAX_NUM_SUB_PLANES; i++) {
141 struct xilinx_drm_plane_dma *dma = &plane->dma[i];
142
143 if (dma->chan && dma->is_active) {
144 flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
145 desc = dmaengine_prep_interleaved_dma(dma->chan,
146 &dma->xt,
147 flags);
148 if (!desc) {
149 DRM_ERROR("failed to prepare DMA descriptor\n");
150 return;
151 }
152
153 dmaengine_submit(desc);
154
155 dma_async_issue_pending(dma->chan);
156 }
157 }
158}
159
160
161void xilinx_drm_plane_dpms(struct drm_plane *base_plane, int dpms)
162{
163 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
164 struct xilinx_drm_plane_manager *manager = plane->manager;
165 unsigned int i;
166
167 DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
168 DRM_DEBUG_KMS("dpms: %d -> %d\n", plane->dpms, dpms);
169
170 if (plane->dpms == dpms)
171 return;
172
173 plane->dpms = dpms;
174 switch (dpms) {
175 case DRM_MODE_DPMS_ON:
176 if (manager->dp_sub) {
177 if (plane->primary) {
178 xilinx_drm_dp_sub_enable_alpha(manager->dp_sub,
179 plane->alpha_enable);
180 xilinx_drm_dp_sub_set_alpha(manager->dp_sub,
181 plane->alpha);
182 }
183 xilinx_drm_dp_sub_layer_enable(manager->dp_sub,
184 plane->dp_layer);
185 }
186
187 if (plane->rgb2yuv)
188 xilinx_rgb2yuv_enable(plane->rgb2yuv);
189
190 if (plane->cresample)
191 xilinx_cresample_enable(plane->cresample);
192
193
194 if (manager->osd) {
195 xilinx_osd_disable_rue(manager->osd);
196
197 xilinx_osd_layer_set_priority(plane->osd_layer,
198 plane->prio);
199 xilinx_osd_layer_enable_alpha(plane->osd_layer,
200 plane->alpha_enable);
201 xilinx_osd_layer_set_alpha(plane->osd_layer,
202 plane->alpha);
203 xilinx_osd_layer_enable(plane->osd_layer);
204
205 xilinx_osd_enable_rue(manager->osd);
206 }
207
208 xilinx_drm_plane_commit(base_plane);
209 break;
210 default:
211
212 if (manager->osd) {
213 xilinx_osd_disable_rue(manager->osd);
214
215 xilinx_osd_layer_set_dimension(plane->osd_layer,
216 0, 0, 0, 0);
217 xilinx_osd_layer_disable(plane->osd_layer);
218
219 xilinx_osd_enable_rue(manager->osd);
220 }
221
222 if (plane->cresample) {
223 xilinx_cresample_disable(plane->cresample);
224 xilinx_cresample_reset(plane->cresample);
225 }
226
227 if (plane->rgb2yuv) {
228 xilinx_rgb2yuv_disable(plane->rgb2yuv);
229 xilinx_rgb2yuv_reset(plane->rgb2yuv);
230 }
231
232
233 for (i = 0; i < MAX_NUM_SUB_PLANES; i++) {
234 if (plane->dma[i].chan && plane->dma[i].is_active)
235 dmaengine_terminate_all(plane->dma[i].chan);
236 }
237
238 if (manager->dp_sub)
239 xilinx_drm_dp_sub_layer_disable(manager->dp_sub,
240 plane->dp_layer);
241
242 break;
243 }
244}
245
246
247int xilinx_drm_plane_mode_set(struct drm_plane *base_plane,
248 struct drm_framebuffer *fb,
249 int crtc_x, int crtc_y,
250 unsigned int crtc_w, unsigned int crtc_h,
251 u32 src_x, u32 src_y,
252 u32 src_w, u32 src_h)
253{
254 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
255 struct drm_gem_cma_object *obj;
256 size_t offset;
257 unsigned int hsub, vsub, i;
258
259 DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
260
261
262 if (plane->cresample)
263 xilinx_cresample_configure(plane->cresample, crtc_w, crtc_h);
264
265
266 if (plane->rgb2yuv)
267 xilinx_rgb2yuv_configure(plane->rgb2yuv, crtc_w, crtc_h);
268
269 DRM_DEBUG_KMS("h: %d(%d), v: %d(%d)\n",
270 src_w, crtc_x, src_h, crtc_y);
271 DRM_DEBUG_KMS("bpp: %d\n", fb->bits_per_pixel / 8);
272
273 hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
274 vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
275
276 for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
277 unsigned int width = src_w / (i ? hsub : 1);
278 unsigned int height = src_h / (i ? vsub : 1);
279 unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, i);
280
281 if (!cpp)
282 cpp = xilinx_drm_format_bpp(fb->pixel_format) >> 3;
283
284 obj = xilinx_drm_fb_get_gem_obj(fb, i);
285 if (!obj) {
286 DRM_ERROR("failed to get a gem obj for fb\n");
287 return -EINVAL;
288 }
289
290 plane->dma[i].xt.numf = height;
291 plane->dma[i].sgl[0].size = width * cpp;
292 plane->dma[i].sgl[0].icg = fb->pitches[i] -
293 plane->dma[i].sgl[0].size;
294 offset = src_x * cpp + src_y * fb->pitches[i];
295 offset += fb->offsets[i];
296 plane->dma[i].xt.src_start = obj->paddr + offset;
297 plane->dma[i].xt.frame_size = 1;
298 plane->dma[i].xt.dir = DMA_MEM_TO_DEV;
299 plane->dma[i].xt.src_sgl = true;
300 plane->dma[i].xt.dst_sgl = false;
301 plane->dma[i].is_active = true;
302 }
303
304 for (; i < MAX_NUM_SUB_PLANES; i++)
305 plane->dma[i].is_active = false;
306
307
308 if (plane->manager->osd) {
309 xilinx_osd_disable_rue(plane->manager->osd);
310
311 xilinx_osd_layer_set_dimension(plane->osd_layer, crtc_x, crtc_y,
312 src_w, src_h);
313
314 xilinx_osd_enable_rue(plane->manager->osd);
315 }
316
317 if (plane->manager->dp_sub) {
318 int ret;
319
320 ret = xilinx_drm_dp_sub_layer_check_size(plane->manager->dp_sub,
321 plane->dp_layer,
322 src_w, src_h);
323 if (ret)
324 return ret;
325
326 ret = xilinx_drm_dp_sub_layer_set_fmt(plane->manager->dp_sub,
327 plane->dp_layer,
328 fb->pixel_format);
329 if (ret) {
330 DRM_ERROR("failed to set dp_sub layer fmt\n");
331 return ret;
332 }
333 }
334
335 return 0;
336}
337
338
339static int xilinx_drm_plane_update(struct drm_plane *base_plane,
340 struct drm_crtc *crtc,
341 struct drm_framebuffer *fb,
342 int crtc_x, int crtc_y,
343 unsigned int crtc_w, unsigned int crtc_h,
344 u32 src_x, u32 src_y,
345 u32 src_w, u32 src_h)
346{
347 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
348 int ret;
349
350 ret = xilinx_drm_plane_mode_set(base_plane, fb,
351 crtc_x, crtc_y, crtc_w, crtc_h,
352 src_x >> 16, src_y >> 16,
353 src_w >> 16, src_h >> 16);
354 if (ret) {
355 DRM_ERROR("failed to mode-set a plane\n");
356 return ret;
357 }
358
359
360 if (plane->dpms != DRM_MODE_DPMS_ON)
361 xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_ON);
362 else
363 xilinx_drm_plane_commit(base_plane);
364
365 return 0;
366}
367
368
369static int xilinx_drm_plane_disable(struct drm_plane *base_plane)
370{
371 xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_OFF);
372
373 return 0;
374}
375
376
377static void xilinx_drm_plane_destroy(struct drm_plane *base_plane)
378{
379 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
380 unsigned int i;
381
382 xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_OFF);
383
384 plane->manager->planes[plane->id] = NULL;
385
386 drm_plane_cleanup(base_plane);
387
388 for (i = 0; i < MAX_NUM_SUB_PLANES; i++)
389 if (plane->dma[i].chan)
390 dma_release_channel(plane->dma[i].chan);
391
392 if (plane->manager->osd) {
393 xilinx_osd_layer_disable(plane->osd_layer);
394 xilinx_osd_layer_put(plane->osd_layer);
395 }
396
397 if (plane->manager->dp_sub) {
398 xilinx_drm_dp_sub_layer_disable(plane->manager->dp_sub,
399 plane->dp_layer);
400 xilinx_drm_dp_sub_layer_put(plane->manager->dp_sub,
401 plane->dp_layer);
402 }
403}
404
405
406
407
408
409
410
411
412
413
414
415
416static void
417xilinx_drm_plane_update_prio(struct xilinx_drm_plane_manager *manager)
418{
419 struct xilinx_drm_plane *planes[MAX_PLANES];
420 struct xilinx_drm_plane *plane;
421 unsigned int i, j;
422
423
424 for (i = 0; i < manager->num_planes; i++) {
425 plane = manager->planes[i];
426
427 for (j = i; j > 0; --j) {
428 if (planes[j - 1]->zpos <= plane->zpos)
429 break;
430 planes[j] = planes[j - 1];
431 }
432
433 planes[j] = plane;
434 }
435
436 xilinx_osd_disable_rue(manager->osd);
437
438
439 for (i = 0; i < manager->num_planes; i++) {
440 planes[i]->prio = i;
441 xilinx_osd_layer_set_priority(planes[i]->osd_layer,
442 planes[i]->prio);
443 }
444
445 xilinx_osd_enable_rue(manager->osd);
446}
447
448static void xilinx_drm_plane_set_zpos(struct drm_plane *base_plane,
449 unsigned int zpos)
450{
451 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
452 struct xilinx_drm_plane_manager *manager = plane->manager;
453 bool update = false;
454 int i;
455
456 for (i = 0; i < manager->num_planes; i++) {
457 if (manager->planes[i] != plane &&
458 manager->planes[i]->prio == zpos) {
459 update = true;
460 break;
461 }
462 }
463
464 plane->zpos = zpos;
465
466 if (update) {
467 xilinx_drm_plane_update_prio(manager);
468 } else {
469 plane->prio = zpos;
470 xilinx_osd_layer_set_priority(plane->osd_layer, plane->prio);
471 }
472}
473
474static void xilinx_drm_plane_set_alpha(struct drm_plane *base_plane,
475 unsigned int alpha)
476{
477 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
478 struct xilinx_drm_plane_manager *manager = plane->manager;
479
480 plane->alpha = alpha;
481
482 if (plane->osd_layer)
483 xilinx_osd_layer_set_alpha(plane->osd_layer, plane->alpha);
484 else if (manager->dp_sub)
485 xilinx_drm_dp_sub_set_alpha(manager->dp_sub, plane->alpha);
486}
487
488static void xilinx_drm_plane_enable_alpha(struct drm_plane *base_plane,
489 bool enable)
490{
491 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
492 struct xilinx_drm_plane_manager *manager = plane->manager;
493
494 plane->alpha_enable = enable;
495
496 if (plane->osd_layer)
497 xilinx_osd_layer_enable_alpha(plane->osd_layer, enable);
498 else if (manager->dp_sub)
499 xilinx_drm_dp_sub_enable_alpha(manager->dp_sub, enable);
500}
501
502
503static int xilinx_drm_plane_set_property(struct drm_plane *base_plane,
504 struct drm_property *property,
505 uint64_t val)
506{
507 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
508 struct xilinx_drm_plane_manager *manager = plane->manager;
509
510 if (property == manager->zpos_prop)
511 xilinx_drm_plane_set_zpos(base_plane, val);
512 else if (property == manager->alpha_prop)
513 xilinx_drm_plane_set_alpha(base_plane, val);
514 else if (property == manager->alpha_enable_prop)
515 xilinx_drm_plane_enable_alpha(base_plane, val);
516 else
517 return -EINVAL;
518
519 drm_object_property_set_value(&base_plane->base, property, val);
520
521 return 0;
522}
523
524static struct drm_plane_funcs xilinx_drm_plane_funcs = {
525 .update_plane = xilinx_drm_plane_update,
526 .disable_plane = xilinx_drm_plane_disable,
527 .destroy = xilinx_drm_plane_destroy,
528 .set_property = xilinx_drm_plane_set_property,
529};
530
531
532int xilinx_drm_plane_get_max_width(struct drm_plane *base_plane)
533{
534 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
535
536 return plane->manager->max_width;
537}
538
539
540bool xilinx_drm_plane_check_format(struct xilinx_drm_plane_manager *manager,
541 u32 format)
542{
543 int i;
544
545 for (i = 0; i < MAX_PLANES; i++)
546 if (manager->planes[i] &&
547 (manager->planes[i]->format == format))
548 return true;
549
550 return false;
551}
552
553
554int xilinx_drm_plane_get_num_planes(struct xilinx_drm_plane_manager *manager)
555{
556 return manager->num_planes;
557}
558
559
560
561
562
563
564
565
566
567
568void xilinx_drm_plane_restore(struct xilinx_drm_plane_manager *manager)
569{
570 struct xilinx_drm_plane *plane;
571 unsigned int i;
572
573
574
575
576
577
578 for (i = 0; i < manager->num_planes; i++) {
579 plane = manager->planes[i];
580
581 plane->prio = plane->id;
582 plane->zpos = plane->id;
583 if (manager->zpos_prop)
584 drm_object_property_set_value(&plane->base.base,
585 manager->zpos_prop,
586 plane->prio);
587
588 plane->alpha = manager->default_alpha;
589 if (manager->alpha_prop)
590 drm_object_property_set_value(&plane->base.base,
591 manager->alpha_prop,
592 plane->alpha);
593
594 plane->alpha_enable = true;
595 if (manager->alpha_enable_prop)
596 drm_object_property_set_value(&plane->base.base,
597 manager->alpha_enable_prop, true);
598 }
599}
600
601
602u32 xilinx_drm_plane_get_format(struct drm_plane *base_plane)
603{
604 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
605
606 return plane->format;
607}
608
609
610
611
612
613
614
615
616
617unsigned int xilinx_drm_plane_get_align(struct drm_plane *base_plane)
618{
619 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
620
621 return 1 << plane->dma[0].chan->device->copy_align;
622}
623
624
625static void
626xilinx_drm_plane_create_property(struct xilinx_drm_plane_manager *manager)
627{
628 if (manager->osd)
629 manager->zpos_prop = drm_property_create_range(manager->drm, 0,
630 "zpos", 0, manager->num_planes - 1);
631
632 if (manager->osd || manager->dp_sub) {
633 manager->alpha_prop = drm_property_create_range(manager->drm, 0,
634 "alpha", 0, manager->default_alpha);
635 manager->alpha_enable_prop =
636 drm_property_create_bool(manager->drm, 0,
637 "global alpha enable");
638 }
639}
640
641
642static void xilinx_drm_plane_attach_property(struct drm_plane *base_plane)
643{
644 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
645 struct xilinx_drm_plane_manager *manager = plane->manager;
646
647 if (manager->zpos_prop)
648 drm_object_attach_property(&base_plane->base,
649 manager->zpos_prop,
650 plane->id);
651
652 if (manager->alpha_prop) {
653 if (manager->dp_sub && !plane->primary)
654 return;
655
656 drm_object_attach_property(&base_plane->base,
657 manager->alpha_prop,
658 manager->default_alpha);
659 drm_object_attach_property(&base_plane->base,
660 manager->alpha_enable_prop, false);
661 }
662
663 plane->alpha_enable = true;
664}
665
666
667
668
669
670
671
672
673
674void xilinx_drm_plane_manager_dpms(struct xilinx_drm_plane_manager *manager,
675 int dpms)
676{
677 switch (dpms) {
678 case DRM_MODE_DPMS_ON:
679 if (manager->dp_sub) {
680 xilinx_drm_dp_sub_set_bg_color(manager->dp_sub,
681 0, 0, 0);
682 xilinx_drm_dp_sub_enable(manager->dp_sub);
683 }
684
685 if (manager->osd) {
686 xilinx_osd_disable_rue(manager->osd);
687 xilinx_osd_enable(manager->osd);
688 xilinx_osd_enable_rue(manager->osd);
689 }
690
691 break;
692 default:
693 if (manager->osd)
694 xilinx_osd_reset(manager->osd);
695
696 if (manager->dp_sub)
697 xilinx_drm_dp_sub_disable(manager->dp_sub);
698
699 break;
700 }
701}
702
703
704
705
706
707
708
709
710
711
712void xilinx_drm_plane_manager_mode_set(struct xilinx_drm_plane_manager *manager,
713 unsigned int crtc_w, unsigned int crtc_h)
714{
715 if (manager->osd)
716 xilinx_osd_set_dimension(manager->osd, crtc_w, crtc_h);
717}
718
719
720static struct xilinx_drm_plane *
721xilinx_drm_plane_create(struct xilinx_drm_plane_manager *manager,
722 unsigned int possible_crtcs, bool primary)
723{
724 struct xilinx_drm_plane *plane;
725 struct device *dev = manager->drm->dev;
726 char plane_name[16];
727 struct device_node *plane_node;
728 struct device_node *sub_node;
729 struct property *prop;
730 const char *dma_name;
731 enum drm_plane_type type;
732 u32 fmt_in = 0;
733 u32 fmt_out = 0;
734 const char *fmt;
735 int i;
736 int ret;
737 u32 *fmts = NULL;
738 unsigned int num_fmts = 0;
739
740 for (i = 0; i < manager->num_planes; i++)
741 if (!manager->planes[i])
742 break;
743
744 if (i >= manager->num_planes) {
745 DRM_ERROR("failed to allocate plane\n");
746 return ERR_PTR(-ENODEV);
747 }
748
749 snprintf(plane_name, sizeof(plane_name), "plane%d", i);
750 plane_node = of_get_child_by_name(manager->node, plane_name);
751 if (!plane_node) {
752 DRM_ERROR("failed to find a plane node\n");
753 return ERR_PTR(-ENODEV);
754 }
755
756 plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL);
757 if (!plane) {
758 ret = -ENOMEM;
759 goto err_out;
760 }
761
762 plane->primary = primary;
763 plane->id = i;
764 plane->prio = i;
765 plane->zpos = i;
766 plane->alpha = manager->default_alpha;
767 plane->dpms = DRM_MODE_DPMS_OFF;
768 plane->format = 0;
769 DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
770
771 i = 0;
772 of_property_for_each_string(plane_node, "dma-names", prop, dma_name) {
773 if (i >= MAX_NUM_SUB_PLANES) {
774 DRM_WARN("%s contains too many sub-planes (dma-names), indexes %d and above ignored\n",
775 of_node_full_name(plane_node),
776 MAX_NUM_SUB_PLANES);
777 break;
778 }
779 plane->dma[i].chan = of_dma_request_slave_channel(plane_node,
780 dma_name);
781 if (IS_ERR(plane->dma[i].chan)) {
782 ret = PTR_ERR(plane->dma[i].chan);
783 DRM_ERROR("failed to request dma channel \"%s\" for plane %s (err:%d)\n",
784 dma_name, of_node_full_name(plane_node), ret);
785 plane->dma[i].chan = NULL;
786 goto err_dma;
787 }
788 ++i;
789 }
790
791 if (i == 0) {
792 DRM_ERROR("plane \"%s\" doesn't have any dma channels (dma-names)\n",
793 of_node_full_name(plane_node));
794 ret = -EINVAL;
795 goto err_out;
796 }
797
798
799 sub_node = of_parse_phandle(plane_node, "xlnx,rgb2yuv", i);
800 if (sub_node) {
801 plane->rgb2yuv = xilinx_rgb2yuv_probe(dev, sub_node);
802 of_node_put(sub_node);
803 if (IS_ERR(plane->rgb2yuv)) {
804 DRM_ERROR("failed to probe a rgb2yuv\n");
805 ret = PTR_ERR(plane->rgb2yuv);
806 goto err_dma;
807 }
808
809
810 plane->format = DRM_FORMAT_XRGB8888;
811
812
813 fmt_out = DRM_FORMAT_YUV444;
814 }
815
816
817 sub_node = of_parse_phandle(plane_node, "xlnx,cresample", i);
818 if (sub_node) {
819 plane->cresample = xilinx_cresample_probe(dev, sub_node);
820 of_node_put(sub_node);
821 if (IS_ERR(plane->cresample)) {
822 DRM_ERROR("failed to probe a cresample\n");
823 ret = PTR_ERR(plane->cresample);
824 goto err_dma;
825 }
826
827
828 fmt = xilinx_cresample_get_input_format_name(plane->cresample);
829 ret = xilinx_drm_format_by_name(fmt, &fmt_in);
830 if (ret)
831 goto err_dma;
832
833
834 if ((fmt_out != 0) && (fmt_out != fmt_in)) {
835 DRM_ERROR("input/output format mismatch\n");
836 ret = -EINVAL;
837 goto err_dma;
838 }
839
840 if (plane->format == 0)
841 plane->format = fmt_in;
842
843
844 fmt = xilinx_cresample_get_output_format_name(plane->cresample);
845 ret = xilinx_drm_format_by_name(fmt, &fmt_out);
846 if (ret)
847 goto err_dma;
848 }
849
850
851 if (manager->osd) {
852
853 if ((fmt_out != 0) && (fmt_out != manager->format)) {
854 DRM_ERROR("input/output format mismatch\n");
855 ret = -EINVAL;
856 goto err_dma;
857 }
858
859
860 plane->osd_layer = xilinx_osd_layer_get(manager->osd);
861 if (IS_ERR(plane->osd_layer)) {
862 DRM_ERROR("failed to create a osd layer\n");
863 ret = PTR_ERR(plane->osd_layer);
864 plane->osd_layer = NULL;
865 goto err_dma;
866 }
867
868 if (plane->format == 0)
869 plane->format = manager->format;
870 }
871
872 if (manager->dp_sub) {
873 plane->dp_layer = xilinx_drm_dp_sub_layer_get(manager->dp_sub,
874 primary);
875 if (IS_ERR(plane->dp_layer)) {
876 DRM_ERROR("failed to create a dp_sub layer\n");
877 ret = PTR_ERR(plane->dp_layer);
878 plane->dp_layer = NULL;
879 goto err_dma;
880 }
881
882 if (primary) {
883 ret = xilinx_drm_dp_sub_layer_set_fmt(manager->dp_sub,
884 plane->dp_layer,
885 manager->format);
886 if (ret) {
887 DRM_ERROR("failed to set dp_sub layer fmt\n");
888 goto err_dma;
889 }
890 }
891
892 plane->format =
893 xilinx_drm_dp_sub_layer_get_fmt(manager->dp_sub,
894 plane->dp_layer);
895 xilinx_drm_dp_sub_layer_get_fmts(manager->dp_sub,
896 plane->dp_layer, &fmts,
897 &num_fmts);
898 }
899
900
901 if (plane->format == 0)
902 plane->format = manager->format;
903
904
905 type = primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
906 ret = drm_universal_plane_init(manager->drm, &plane->base,
907 possible_crtcs, &xilinx_drm_plane_funcs,
908 fmts ? fmts : &plane->format,
909 num_fmts ? num_fmts : 1, type, NULL);
910 if (ret) {
911 DRM_ERROR("failed to initialize plane\n");
912 goto err_init;
913 }
914 plane->manager = manager;
915 manager->planes[plane->id] = plane;
916
917 xilinx_drm_plane_attach_property(&plane->base);
918
919 of_node_put(plane_node);
920
921 return plane;
922
923err_init:
924 if (manager->dp_sub) {
925 xilinx_drm_dp_sub_layer_disable(manager->dp_sub,
926 plane->dp_layer);
927 xilinx_drm_dp_sub_layer_put(plane->manager->dp_sub,
928 plane->dp_layer);
929 }
930 if (manager->osd) {
931 xilinx_osd_layer_disable(plane->osd_layer);
932 xilinx_osd_layer_put(plane->osd_layer);
933 }
934err_dma:
935 for (i = 0; i < MAX_NUM_SUB_PLANES; i++)
936 if (plane->dma[i].chan)
937 dma_release_channel(plane->dma[i].chan);
938err_out:
939 of_node_put(plane_node);
940 return ERR_PTR(ret);
941}
942
943
944struct drm_plane *
945xilinx_drm_plane_create_primary(struct xilinx_drm_plane_manager *manager,
946 unsigned int possible_crtcs)
947{
948 struct xilinx_drm_plane *plane;
949
950 plane = xilinx_drm_plane_create(manager, possible_crtcs, true);
951 if (IS_ERR(plane)) {
952 DRM_ERROR("failed to allocate a primary plane\n");
953 return ERR_CAST(plane);
954 }
955
956 return &plane->base;
957}
958
959
960int xilinx_drm_plane_create_planes(struct xilinx_drm_plane_manager *manager,
961 unsigned int possible_crtcs)
962{
963 struct xilinx_drm_plane *plane;
964 int i;
965
966
967 for (i = 0; i < manager->num_planes; i++) {
968 if (manager->planes[i])
969 continue;
970
971 plane = xilinx_drm_plane_create(manager, possible_crtcs, false);
972 if (IS_ERR(plane)) {
973 DRM_ERROR("failed to allocate a plane\n");
974 return PTR_ERR(plane);
975 }
976
977 manager->planes[i] = plane;
978 }
979
980 return 0;
981}
982
983
984static int
985xilinx_drm_plane_init_manager(struct xilinx_drm_plane_manager *manager)
986{
987 unsigned int format;
988 u32 drm_format;
989 int ret = 0;
990
991 if (manager->osd) {
992 manager->num_planes = xilinx_osd_get_num_layers(manager->osd);
993 manager->max_width = xilinx_osd_get_max_width(manager->osd);
994
995 format = xilinx_osd_get_format(manager->osd);
996 ret = xilinx_drm_format_by_code(format, &drm_format);
997 if (drm_format != manager->format)
998 ret = -EINVAL;
999 } else if (manager->dp_sub) {
1000 manager->num_planes = XILINX_DRM_DP_SUB_NUM_LAYERS;
1001 manager->max_width = XILINX_DRM_DP_SUB_MAX_WIDTH;
1002 } else {
1003
1004 manager->num_planes = 1;
1005 manager->max_width = 4096;
1006 }
1007
1008 return ret;
1009}
1010
1011struct xilinx_drm_plane_manager *
1012xilinx_drm_plane_probe_manager(struct drm_device *drm)
1013{
1014 struct xilinx_drm_plane_manager *manager;
1015 struct device *dev = drm->dev;
1016 struct device_node *sub_node;
1017 const char *format;
1018 int ret;
1019
1020 manager = devm_kzalloc(dev, sizeof(*manager), GFP_KERNEL);
1021 if (!manager)
1022 return ERR_PTR(-ENOMEM);
1023
1024
1025 manager->node = of_get_child_by_name(dev->of_node, "planes");
1026 if (!manager->node) {
1027 DRM_ERROR("failed to get a planes node\n");
1028 return ERR_PTR(-EINVAL);
1029 }
1030
1031
1032 ret = of_property_read_string(manager->node, "xlnx,pixel-format",
1033 &format);
1034 if (ret < 0) {
1035 DRM_ERROR("failed to get a plane manager format\n");
1036 return ERR_PTR(ret);
1037 }
1038
1039 ret = xilinx_drm_format_by_name(format, &manager->format);
1040 if (ret < 0) {
1041 DRM_ERROR("invalid plane manager format\n");
1042 return ERR_PTR(ret);
1043 }
1044
1045 manager->drm = drm;
1046
1047
1048 sub_node = of_parse_phandle(dev->of_node, "xlnx,osd", 0);
1049 if (sub_node) {
1050 manager->osd = xilinx_osd_probe(dev, sub_node);
1051 of_node_put(sub_node);
1052 if (IS_ERR(manager->osd)) {
1053 of_node_put(manager->node);
1054 DRM_ERROR("failed to probe an osd\n");
1055 return ERR_CAST(manager->osd);
1056 }
1057 manager->default_alpha = OSD_MAX_ALPHA;
1058 }
1059
1060 manager->dp_sub = xilinx_drm_dp_sub_of_get(drm->dev->of_node);
1061 if (IS_ERR(manager->dp_sub)) {
1062 DRM_DEBUG_KMS("failed to get a dp_sub\n");
1063 return ERR_CAST(manager->dp_sub);
1064 } else if (manager->dp_sub) {
1065 manager->default_alpha = XILINX_DRM_DP_SUB_MAX_ALPHA;
1066 }
1067
1068 ret = xilinx_drm_plane_init_manager(manager);
1069 if (ret) {
1070 DRM_ERROR("failed to init a plane manager\n");
1071 return ERR_PTR(ret);
1072 }
1073
1074 xilinx_drm_plane_create_property(manager);
1075
1076 return manager;
1077}
1078
1079void xilinx_drm_plane_remove_manager(struct xilinx_drm_plane_manager *manager)
1080{
1081 xilinx_drm_dp_sub_put(manager->dp_sub);
1082 of_node_put(manager->node);
1083}
1084