]> rtime.felk.cvut.cz Git - zynq/linux.git/blob - drivers/gpu/drm/xilinx/xilinx_drm_plane.c
drm: xilinx: plane: Use drm_format_plane_width_bytes
[zynq/linux.git] / drivers / gpu / drm / xilinx / xilinx_drm_plane.c
1 /*
2  * Xilinx DRM plane driver for Xilinx
3  *
4  *  Copyright (C) 2013 Xilinx, Inc.
5  *
6  *  Author: Hyun Woo Kwon <hyunk@xilinx.com>
7  *
8  * This software is licensed under the terms of the GNU General Public
9  * License version 2, as published by the Free Software Foundation, and
10  * may be copied, distributed, and modified under those terms.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
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  * struct xilinx_drm_plane_dma - Xilinx drm plane VDMA object
43  *
44  * @chan: dma channel
45  * @xt: dma interleaved configuration template
46  * @sgl: data chunk for dma_interleaved_template
47  * @is_active: flag if the DMA is active
48  */
49 struct 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  * struct xilinx_drm_plane - Xilinx drm plane object
58  *
59  * @base: base drm plane object
60  * @id: plane id
61  * @dpms: current dpms level
62  * @zpos: user requested z-position value
63  * @prio: actual layer priority
64  * @alpha: alpha value
65  * @alpha_enable: alpha enable value
66  * @primary: flag for primary plane
67  * @format: pixel format
68  * @dma: dma object
69  * @rgb2yuv: rgb2yuv instance
70  * @cresample: cresample instance
71  * @osd_layer: osd layer
72  * @dp_layer: DisplayPort subsystem layer
73  * @manager: plane manager
74  */
75 struct 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  * struct xilinx_drm_plane_manager - Xilinx drm plane manager object
97  *
98  * @drm: drm device
99  * @node: plane device node
100  * @osd: osd instance
101  * @dp_sub: DisplayPort subsystem instance
102  * @num_planes: number of available planes
103  * @format: video format
104  * @max_width: maximum width
105  * @zpos_prop: z-position(priority) property
106  * @alpha_prop: alpha value property
107  * @alpha_enable_prop: alpha enable property
108  * @default_alpha: default alpha value
109  * @planes: xilinx drm planes
110  */
111 struct 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
128 void 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         /* for xilinx video framebuffer dma, if used */
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 /* set plane dpms */
161 void 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                 /* enable osd */
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                 /* disable/reset osd */
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                 /* stop dma engine and release descriptors */
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 /* mode set a plane */
247 int 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         const struct drm_format_info *info;
257         struct drm_format_name_buf format_name;
258         size_t offset;
259         unsigned int hsub, vsub, i;
260
261         DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
262
263         /* configure cresample */
264         if (plane->cresample)
265                 xilinx_cresample_configure(plane->cresample, crtc_w, crtc_h);
266
267         /* configure rgb2yuv */
268         if (plane->rgb2yuv)
269                 xilinx_rgb2yuv_configure(plane->rgb2yuv, crtc_w, crtc_h);
270
271         DRM_DEBUG_KMS("h: %d(%d), v: %d(%d)\n",
272                       src_w, crtc_x, src_h, crtc_y);
273         DRM_DEBUG_KMS("bpp: %d\n", fb->format->cpp[0] * 8);
274
275         info = fb->format;
276         if (!info) {
277                 DRM_ERROR("Unsupported framebuffer format %s\n",
278                           drm_get_format_name(info->format, &format_name));
279                 return -EINVAL;
280         }
281
282         hsub = info->hsub;
283         vsub = info->vsub;
284
285         for (i = 0; i < info->num_planes; i++) {
286                 unsigned int width = src_w / (i ? hsub : 1);
287                 unsigned int height = src_h / (i ? vsub : 1);
288                 unsigned int cpp = info->cpp[i];
289
290                 if (!cpp)
291                         cpp = xilinx_drm_format_bpp(fb->format->format) >> 3;
292
293                 obj = xilinx_drm_fb_get_gem_obj(fb, i);
294                 if (!obj) {
295                         DRM_ERROR("failed to get a gem obj for fb\n");
296                         return -EINVAL;
297                 }
298
299                 plane->dma[i].xt.numf = height;
300                 plane->dma[i].sgl[0].size = drm_format_plane_width_bytes(info,
301                                                                          i,
302                                                                          width);
303                 plane->dma[i].sgl[0].icg = fb->pitches[i] -
304                                            plane->dma[i].sgl[0].size;
305                 offset = drm_format_plane_width_bytes(info, i, src_x);
306                 offset += src_y * fb->pitches[i];
307                 offset += fb->offsets[i];
308                 plane->dma[i].xt.src_start = obj->paddr + offset;
309                 plane->dma[i].xt.frame_size = 1;
310                 plane->dma[i].xt.dir = DMA_MEM_TO_DEV;
311                 plane->dma[i].xt.src_sgl = true;
312                 plane->dma[i].xt.dst_sgl = false;
313                 plane->dma[i].is_active = true;
314         }
315
316         for (; i < MAX_NUM_SUB_PLANES; i++)
317                 plane->dma[i].is_active = false;
318
319         /* set OSD dimensions */
320         if (plane->manager->osd) {
321                 xilinx_osd_disable_rue(plane->manager->osd);
322
323                 xilinx_osd_layer_set_dimension(plane->osd_layer, crtc_x, crtc_y,
324                                                src_w, src_h);
325
326                 xilinx_osd_enable_rue(plane->manager->osd);
327         }
328
329         if (plane->manager->dp_sub) {
330                 int ret;
331
332                 ret = xilinx_drm_dp_sub_layer_check_size(plane->manager->dp_sub,
333                                                          plane->dp_layer,
334                                                          src_w, src_h);
335                 if (ret)
336                         return ret;
337
338                 ret = xilinx_drm_dp_sub_layer_set_fmt(plane->manager->dp_sub,
339                                                       plane->dp_layer,
340                                                       fb->format->format);
341                 if (ret) {
342                         DRM_ERROR("failed to set dp_sub layer fmt\n");
343                         return ret;
344                 }
345         }
346
347         return 0;
348 }
349
350 /* update a plane. just call mode_set() with bit-shifted values */
351 static int xilinx_drm_plane_update(struct drm_plane *base_plane,
352                                    struct drm_crtc *crtc,
353                                    struct drm_framebuffer *fb,
354                                    int crtc_x, int crtc_y,
355                                    unsigned int crtc_w, unsigned int crtc_h,
356                                    u32 src_x, u32 src_y,
357                                    u32 src_w, u32 src_h,
358                                    struct drm_modeset_acquire_ctx *ctx)
359 {
360         struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
361         int ret;
362
363         ret = xilinx_drm_plane_mode_set(base_plane, fb,
364                                         crtc_x, crtc_y, crtc_w, crtc_h,
365                                         src_x >> 16, src_y >> 16,
366                                         src_w >> 16, src_h >> 16);
367         if (ret) {
368                 DRM_ERROR("failed to mode-set a plane\n");
369                 return ret;
370         }
371
372         /* make sure a plane is on */
373         if (plane->dpms != DRM_MODE_DPMS_ON)
374                 xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_ON);
375         else
376                 xilinx_drm_plane_commit(base_plane);
377
378         return 0;
379 }
380
381 /* disable a plane */
382 static int xilinx_drm_plane_disable(struct drm_plane *base_plane,
383                                     struct drm_modeset_acquire_ctx *ctx)
384 {
385         xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_OFF);
386
387         return 0;
388 }
389
390 /* destroy a plane */
391 static void xilinx_drm_plane_destroy(struct drm_plane *base_plane)
392 {
393         struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
394         unsigned int i;
395
396         xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_OFF);
397
398         plane->manager->planes[plane->id] = NULL;
399
400         drm_plane_cleanup(base_plane);
401
402         for (i = 0; i < MAX_NUM_SUB_PLANES; i++)
403                 if (plane->dma[i].chan)
404                         dma_release_channel(plane->dma[i].chan);
405
406         if (plane->manager->osd) {
407                 xilinx_osd_layer_disable(plane->osd_layer);
408                 xilinx_osd_layer_put(plane->osd_layer);
409         }
410
411         if (plane->manager->dp_sub) {
412                 xilinx_drm_dp_sub_layer_disable(plane->manager->dp_sub,
413                                                 plane->dp_layer);
414                 xilinx_drm_dp_sub_layer_put(plane->manager->dp_sub,
415                                             plane->dp_layer);
416         }
417 }
418
419 /**
420  * xilinx_drm_plane_update_prio - Configure plane priorities based on zpos
421  * @manager: the plane manager
422  *
423  * Z-position values are user requested position of planes. The priority is
424  * the actual position of planes in hardware. Some hardware doesn't allow
425  * any duplicate priority, so this function needs to be called when a duplicate
426  * priority is found. Then planes are sorted by zpos value, and the priorities
427  * are reconfigured. A plane with lower plane ID gets assigned to the lower
428  * priority when planes have the same zpos value.
429  */
430 static void
431 xilinx_drm_plane_update_prio(struct xilinx_drm_plane_manager *manager)
432 {
433         struct xilinx_drm_plane *planes[MAX_PLANES];
434         struct xilinx_drm_plane *plane;
435         unsigned int i, j;
436
437         /* sort planes by zpos */
438         for (i = 0; i < manager->num_planes; i++) {
439                 plane = manager->planes[i];
440
441                 for (j = i; j > 0; --j) {
442                         if (planes[j - 1]->zpos <= plane->zpos)
443                                 break;
444                         planes[j] = planes[j - 1];
445                 }
446
447                 planes[j] = plane;
448         }
449
450         xilinx_osd_disable_rue(manager->osd);
451
452         /* remove duplicates by reassigning priority */
453         for (i = 0; i < manager->num_planes; i++) {
454                 planes[i]->prio = i;
455                 xilinx_osd_layer_set_priority(planes[i]->osd_layer,
456                                               planes[i]->prio);
457         }
458
459         xilinx_osd_enable_rue(manager->osd);
460 }
461
462 static void xilinx_drm_plane_set_zpos(struct drm_plane *base_plane,
463                                       unsigned int zpos)
464 {
465         struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
466         struct xilinx_drm_plane_manager *manager = plane->manager;
467         bool update = false;
468         int i;
469
470         for (i = 0; i < manager->num_planes; i++) {
471                 if (manager->planes[i] != plane &&
472                     manager->planes[i]->prio == zpos) {
473                         update = true;
474                         break;
475                 }
476         }
477
478         plane->zpos = zpos;
479
480         if (update) {
481                 xilinx_drm_plane_update_prio(manager);
482         } else {
483                 plane->prio = zpos;
484                 xilinx_osd_layer_set_priority(plane->osd_layer, plane->prio);
485         }
486 }
487
488 static void xilinx_drm_plane_set_alpha(struct drm_plane *base_plane,
489                                        unsigned int alpha)
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 = alpha;
495
496         if (plane->osd_layer)
497                 xilinx_osd_layer_set_alpha(plane->osd_layer, plane->alpha);
498         else if (manager->dp_sub)
499                 xilinx_drm_dp_sub_set_alpha(manager->dp_sub, plane->alpha);
500 }
501
502 static void xilinx_drm_plane_enable_alpha(struct drm_plane *base_plane,
503                                           bool enable)
504 {
505         struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
506         struct xilinx_drm_plane_manager *manager = plane->manager;
507
508         plane->alpha_enable = enable;
509
510         if (plane->osd_layer)
511                 xilinx_osd_layer_enable_alpha(plane->osd_layer, enable);
512         else if (manager->dp_sub)
513                 xilinx_drm_dp_sub_enable_alpha(manager->dp_sub, enable);
514 }
515
516 /* set property of a plane */
517 static int xilinx_drm_plane_set_property(struct drm_plane *base_plane,
518                                          struct drm_property *property,
519                                          uint64_t val)
520 {
521         struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
522         struct xilinx_drm_plane_manager *manager = plane->manager;
523
524         if (property == manager->zpos_prop)
525                 xilinx_drm_plane_set_zpos(base_plane, val);
526         else if (property == manager->alpha_prop)
527                 xilinx_drm_plane_set_alpha(base_plane, val);
528         else if (property == manager->alpha_enable_prop)
529                 xilinx_drm_plane_enable_alpha(base_plane, val);
530         else
531                 return -EINVAL;
532
533         drm_object_property_set_value(&base_plane->base, property, val);
534
535         return 0;
536 }
537
538 static struct drm_plane_funcs xilinx_drm_plane_funcs = {
539         .update_plane   = xilinx_drm_plane_update,
540         .disable_plane  = xilinx_drm_plane_disable,
541         .destroy        = xilinx_drm_plane_destroy,
542         .set_property   = xilinx_drm_plane_set_property,
543 };
544
545 /* get a plane max width */
546 int xilinx_drm_plane_get_max_width(struct drm_plane *base_plane)
547 {
548         struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
549
550         return plane->manager->max_width;
551 }
552
553 /* check if format is supported */
554 bool xilinx_drm_plane_check_format(struct xilinx_drm_plane_manager *manager,
555                                    u32 format)
556 {
557         int i;
558
559         for (i = 0; i < MAX_PLANES; i++)
560                 if (manager->planes[i] &&
561                     (manager->planes[i]->format == format))
562                         return true;
563
564         return false;
565 }
566
567 /* get the number of planes */
568 int xilinx_drm_plane_get_num_planes(struct xilinx_drm_plane_manager *manager)
569 {
570         return manager->num_planes;
571 }
572
573 /**
574  * xilinx_drm_plane_restore - Restore the plane states
575  * @manager: the plane manager
576  *
577  * Restore the plane states to the default ones. Any state that needs to be
578  * restored should be here. This improves consistency as applications see
579  * the same default values, and removes mismatch between software and hardware
580  * values as software values are updated as hardware values are reset.
581  */
582 void xilinx_drm_plane_restore(struct xilinx_drm_plane_manager *manager)
583 {
584         struct xilinx_drm_plane *plane;
585         unsigned int i;
586
587         /*
588          * Reinitialize property default values as they get reset by DPMS OFF
589          * operation. User will read the correct default values later, and
590          * planes will be initialized with default values.
591          */
592         for (i = 0; i < manager->num_planes; i++) {
593                 plane = manager->planes[i];
594
595                 plane->prio = plane->id;
596                 plane->zpos = plane->id;
597                 if (manager->zpos_prop)
598                         drm_object_property_set_value(&plane->base.base,
599                                                       manager->zpos_prop,
600                                                       plane->prio);
601
602                 plane->alpha = manager->default_alpha;
603                 if (manager->alpha_prop)
604                         drm_object_property_set_value(&plane->base.base,
605                                                       manager->alpha_prop,
606                                                       plane->alpha);
607
608                 plane->alpha_enable = true;
609                 if (manager->alpha_enable_prop)
610                         drm_object_property_set_value(&plane->base.base,
611                                                       manager->alpha_enable_prop, true);
612         }
613 }
614
615 /* get the plane format */
616 u32 xilinx_drm_plane_get_format(struct drm_plane *base_plane)
617 {
618         struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
619
620         return plane->format;
621 }
622
623 /**
624  * xilinx_drm_plane_get_align - Get the alignment value for pitch
625  * @base_plane: Base drm plane object
626  *
627  * Get the alignment value for pitch from the dma device
628  *
629  * Return: The alignment value if successful, or the error code.
630  */
631 unsigned int xilinx_drm_plane_get_align(struct drm_plane *base_plane)
632 {
633         struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
634
635         return 1 << plane->dma[0].chan->device->copy_align;
636 }
637
638 /* create plane properties */
639 static void
640 xilinx_drm_plane_create_property(struct xilinx_drm_plane_manager *manager)
641 {
642         if (manager->osd)
643                 manager->zpos_prop = drm_property_create_range(manager->drm, 0,
644                                 "zpos", 0, manager->num_planes - 1);
645
646         if (manager->osd || manager->dp_sub) {
647                 manager->alpha_prop = drm_property_create_range(manager->drm, 0,
648                                 "alpha", 0, manager->default_alpha);
649                 manager->alpha_enable_prop =
650                         drm_property_create_bool(manager->drm, 0,
651                                                  "global alpha enable");
652         }
653 }
654
655 /* attach plane properties */
656 static void xilinx_drm_plane_attach_property(struct drm_plane *base_plane)
657 {
658         struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
659         struct xilinx_drm_plane_manager *manager = plane->manager;
660
661         if (manager->zpos_prop)
662                 drm_object_attach_property(&base_plane->base,
663                                            manager->zpos_prop,
664                                            plane->id);
665
666         if (manager->alpha_prop) {
667                 if (manager->dp_sub && !plane->primary)
668                         return;
669
670                 drm_object_attach_property(&base_plane->base,
671                                            manager->alpha_prop,
672                                            manager->default_alpha);
673                 drm_object_attach_property(&base_plane->base,
674                                            manager->alpha_enable_prop, false);
675         }
676
677         plane->alpha_enable = true;
678 }
679
680 /**
681  * xilinx_drm_plane_manager_dpms - Set DPMS for the Xilinx plane manager
682  * @manager: Xilinx plane manager object
683  * @dpms: requested DPMS
684  *
685  * Set the Xilinx plane manager to the given DPMS state. This function is
686  * usually called from the CRTC driver with calling xilinx_drm_plane_dpms().
687  */
688 void xilinx_drm_plane_manager_dpms(struct xilinx_drm_plane_manager *manager,
689                                    int dpms)
690 {
691         switch (dpms) {
692         case DRM_MODE_DPMS_ON:
693                 if (manager->dp_sub) {
694                         xilinx_drm_dp_sub_set_bg_color(manager->dp_sub,
695                                                        0, 0, 0);
696                         xilinx_drm_dp_sub_enable(manager->dp_sub);
697                 }
698
699                 if (manager->osd) {
700                         xilinx_osd_disable_rue(manager->osd);
701                         xilinx_osd_enable(manager->osd);
702                         xilinx_osd_enable_rue(manager->osd);
703                 }
704
705                 break;
706         default:
707                 if (manager->osd)
708                         xilinx_osd_reset(manager->osd);
709
710                 if (manager->dp_sub)
711                         xilinx_drm_dp_sub_disable(manager->dp_sub);
712
713                 break;
714         }
715 }
716
717 /**
718  * xilinx_drm_plane_manager_mode_set - Set the mode to the Xilinx plane manager
719  * @manager: Xilinx plane manager object
720  * @crtc_w: CRTC width
721  * @crtc_h: CRTC height
722  *
723  * Set the width and height of the Xilinx plane manager. This function is uaully
724  * called from the CRTC driver before calling the xilinx_drm_plane_mode_set().
725  */
726 void xilinx_drm_plane_manager_mode_set(struct xilinx_drm_plane_manager *manager,
727                                        unsigned int crtc_w, unsigned int crtc_h)
728 {
729         if (manager->osd)
730                 xilinx_osd_set_dimension(manager->osd, crtc_w, crtc_h);
731 }
732
733 /* create a plane */
734 static struct xilinx_drm_plane *
735 xilinx_drm_plane_create(struct xilinx_drm_plane_manager *manager,
736                         unsigned int possible_crtcs, bool primary)
737 {
738         struct xilinx_drm_plane *plane;
739         struct device *dev = manager->drm->dev;
740         char plane_name[16];
741         struct device_node *plane_node;
742         struct device_node *sub_node;
743         struct property *prop;
744         const char *dma_name;
745         enum drm_plane_type type;
746         u32 fmt_in = 0;
747         u32 fmt_out = 0;
748         const char *fmt;
749         int i;
750         int ret;
751         u32 *fmts = NULL;
752         unsigned int num_fmts = 0;
753
754         for (i = 0; i < manager->num_planes; i++)
755                 if (!manager->planes[i])
756                         break;
757
758         if (i >= manager->num_planes) {
759                 DRM_ERROR("failed to allocate plane\n");
760                 return ERR_PTR(-ENODEV);
761         }
762
763         snprintf(plane_name, sizeof(plane_name), "plane%d", i);
764         plane_node = of_get_child_by_name(manager->node, plane_name);
765         if (!plane_node) {
766                 DRM_ERROR("failed to find a plane node\n");
767                 return ERR_PTR(-ENODEV);
768         }
769
770         plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL);
771         if (!plane) {
772                 ret = -ENOMEM;
773                 goto err_out;
774         }
775
776         plane->primary = primary;
777         plane->id = i;
778         plane->prio = i;
779         plane->zpos = i;
780         plane->alpha = manager->default_alpha;
781         plane->dpms = DRM_MODE_DPMS_OFF;
782         plane->format = 0;
783         DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
784
785         i = 0;
786         of_property_for_each_string(plane_node, "dma-names", prop, dma_name) {
787                 if (i >= MAX_NUM_SUB_PLANES) {
788                         DRM_WARN("%s contains too many sub-planes (dma-names), indexes %d and above ignored\n",
789                                  of_node_full_name(plane_node),
790                                  MAX_NUM_SUB_PLANES);
791                         break;
792                 }
793                 plane->dma[i].chan = of_dma_request_slave_channel(plane_node,
794                                                                   dma_name);
795                 if (IS_ERR(plane->dma[i].chan)) {
796                         ret = PTR_ERR(plane->dma[i].chan);
797                         DRM_ERROR("failed to request dma channel \"%s\" for plane %s (err:%d)\n",
798                                   dma_name, of_node_full_name(plane_node), ret);
799                         plane->dma[i].chan = NULL;
800                         goto err_dma;
801                 }
802                 ++i;
803         }
804
805         if (i == 0) {
806                 DRM_ERROR("plane \"%s\" doesn't have any dma channels (dma-names)\n",
807                           of_node_full_name(plane_node));
808                 ret = -EINVAL;
809                 goto err_out;
810         }
811
812         /* probe color space converter */
813         sub_node = of_parse_phandle(plane_node, "xlnx,rgb2yuv", i);
814         if (sub_node) {
815                 plane->rgb2yuv = xilinx_rgb2yuv_probe(dev, sub_node);
816                 of_node_put(sub_node);
817                 if (IS_ERR(plane->rgb2yuv)) {
818                         DRM_ERROR("failed to probe a rgb2yuv\n");
819                         ret = PTR_ERR(plane->rgb2yuv);
820                         goto err_dma;
821                 }
822
823                 /* rgb2yuv input format */
824                 plane->format = DRM_FORMAT_XRGB8888;
825
826                 /* rgb2yuv output format */
827                 fmt_out = DRM_FORMAT_YUV444;
828         }
829
830         /* probe chroma resampler */
831         sub_node = of_parse_phandle(plane_node, "xlnx,cresample", i);
832         if (sub_node) {
833                 plane->cresample = xilinx_cresample_probe(dev, sub_node);
834                 of_node_put(sub_node);
835                 if (IS_ERR(plane->cresample)) {
836                         DRM_ERROR("failed to probe a cresample\n");
837                         ret = PTR_ERR(plane->cresample);
838                         goto err_dma;
839                 }
840
841                 /* cresample input format */
842                 fmt = xilinx_cresample_get_input_format_name(plane->cresample);
843                 ret = xilinx_drm_format_by_name(fmt, &fmt_in);
844                 if (ret)
845                         goto err_dma;
846
847                 /* format sanity check */
848                 if ((fmt_out != 0) && (fmt_out != fmt_in)) {
849                         DRM_ERROR("input/output format mismatch\n");
850                         ret = -EINVAL;
851                         goto err_dma;
852                 }
853
854                 if (plane->format == 0)
855                         plane->format = fmt_in;
856
857                 /* cresample output format */
858                 fmt = xilinx_cresample_get_output_format_name(plane->cresample);
859                 ret = xilinx_drm_format_by_name(fmt, &fmt_out);
860                 if (ret)
861                         goto err_dma;
862         }
863
864         /* create an OSD layer when OSD is available */
865         if (manager->osd) {
866                 /* format sanity check */
867                 if ((fmt_out != 0) && (fmt_out != manager->format)) {
868                         DRM_ERROR("input/output format mismatch\n");
869                         ret = -EINVAL;
870                         goto err_dma;
871                 }
872
873                 /* create an osd layer */
874                 plane->osd_layer = xilinx_osd_layer_get(manager->osd);
875                 if (IS_ERR(plane->osd_layer)) {
876                         DRM_ERROR("failed to create a osd layer\n");
877                         ret = PTR_ERR(plane->osd_layer);
878                         plane->osd_layer = NULL;
879                         goto err_dma;
880                 }
881
882                 if (plane->format == 0)
883                         plane->format = manager->format;
884         }
885
886         if (manager->dp_sub) {
887                 plane->dp_layer = xilinx_drm_dp_sub_layer_get(manager->dp_sub,
888                                                               primary);
889                 if (IS_ERR(plane->dp_layer)) {
890                         DRM_ERROR("failed to create a dp_sub layer\n");
891                         ret = PTR_ERR(plane->dp_layer);
892                         plane->dp_layer = NULL;
893                         goto err_dma;
894                 }
895
896                 if (primary) {
897                         ret = xilinx_drm_dp_sub_layer_set_fmt(manager->dp_sub,
898                                                               plane->dp_layer,
899                                                               manager->format);
900                         if (ret) {
901                                 DRM_ERROR("failed to set dp_sub layer fmt\n");
902                                 goto err_dma;
903                         }
904                 }
905
906                 plane->format =
907                         xilinx_drm_dp_sub_layer_get_fmt(manager->dp_sub,
908                                                         plane->dp_layer);
909                 xilinx_drm_dp_sub_layer_get_fmts(manager->dp_sub,
910                                                  plane->dp_layer, &fmts,
911                                                  &num_fmts);
912         }
913
914         /* If there's no IP other than VDMA, pick the manager's format */
915         if (plane->format == 0)
916                 plane->format = manager->format;
917
918         /* initialize drm plane */
919         type = primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
920         ret = drm_universal_plane_init(manager->drm, &plane->base,
921                                        possible_crtcs, &xilinx_drm_plane_funcs,
922                                        fmts ? fmts : &plane->format,
923                                        num_fmts ? num_fmts : 1, NULL, type,
924                                        NULL);
925         if (ret) {
926                 DRM_ERROR("failed to initialize plane\n");
927                 goto err_init;
928         }
929         plane->manager = manager;
930         manager->planes[plane->id] = plane;
931
932         xilinx_drm_plane_attach_property(&plane->base);
933
934         of_node_put(plane_node);
935
936         return plane;
937
938 err_init:
939         if (manager->dp_sub) {
940                 xilinx_drm_dp_sub_layer_disable(manager->dp_sub,
941                                                 plane->dp_layer);
942                 xilinx_drm_dp_sub_layer_put(plane->manager->dp_sub,
943                                             plane->dp_layer);
944         }
945         if (manager->osd) {
946                 xilinx_osd_layer_disable(plane->osd_layer);
947                 xilinx_osd_layer_put(plane->osd_layer);
948         }
949 err_dma:
950         for (i = 0; i < MAX_NUM_SUB_PLANES; i++)
951                 if (plane->dma[i].chan)
952                         dma_release_channel(plane->dma[i].chan);
953 err_out:
954         of_node_put(plane_node);
955         return ERR_PTR(ret);
956 }
957
958 /* create a primary plane */
959 struct drm_plane *
960 xilinx_drm_plane_create_primary(struct xilinx_drm_plane_manager *manager,
961                                 unsigned int possible_crtcs)
962 {
963         struct xilinx_drm_plane *plane;
964
965         plane = xilinx_drm_plane_create(manager, possible_crtcs, true);
966         if (IS_ERR(plane)) {
967                 DRM_ERROR("failed to allocate a primary plane\n");
968                 return ERR_CAST(plane);
969         }
970
971         return &plane->base;
972 }
973
974 /* create extra planes */
975 int xilinx_drm_plane_create_planes(struct xilinx_drm_plane_manager *manager,
976                                    unsigned int possible_crtcs)
977 {
978         struct xilinx_drm_plane *plane;
979         int i;
980
981         /* find if there any available plane, and create if available */
982         for (i = 0; i < manager->num_planes; i++) {
983                 if (manager->planes[i])
984                         continue;
985
986                 plane = xilinx_drm_plane_create(manager, possible_crtcs, false);
987                 if (IS_ERR(plane)) {
988                         DRM_ERROR("failed to allocate a plane\n");
989                         return PTR_ERR(plane);
990                 }
991
992                 manager->planes[i] = plane;
993         }
994
995         return 0;
996 }
997
998 /* initialize a plane manager: num_planes, format, max_width */
999 static int
1000 xilinx_drm_plane_init_manager(struct xilinx_drm_plane_manager *manager)
1001 {
1002         unsigned int format;
1003         u32 drm_format;
1004         int ret = 0;
1005
1006         if (manager->osd) {
1007                 manager->num_planes = xilinx_osd_get_num_layers(manager->osd);
1008                 manager->max_width = xilinx_osd_get_max_width(manager->osd);
1009
1010                 format = xilinx_osd_get_format(manager->osd);
1011                 ret = xilinx_drm_format_by_code(format, &drm_format);
1012                 if (drm_format != manager->format)
1013                         ret = -EINVAL;
1014         } else if (manager->dp_sub) {
1015                 manager->num_planes = XILINX_DRM_DP_SUB_NUM_LAYERS;
1016                 manager->max_width = XILINX_DRM_DP_SUB_MAX_WIDTH;
1017         } else {
1018                 /* without osd, only one plane is supported */
1019                 manager->num_planes = 1;
1020                 manager->max_width = 4096;
1021         }
1022
1023         return ret;
1024 }
1025
1026 struct xilinx_drm_plane_manager *
1027 xilinx_drm_plane_probe_manager(struct drm_device *drm)
1028 {
1029         struct xilinx_drm_plane_manager *manager;
1030         struct device *dev = drm->dev;
1031         struct device_node *sub_node;
1032         const char *format;
1033         int ret;
1034
1035         manager = devm_kzalloc(dev, sizeof(*manager), GFP_KERNEL);
1036         if (!manager)
1037                 return ERR_PTR(-ENOMEM);
1038
1039         /* this node is used to create a plane */
1040         manager->node = of_get_child_by_name(dev->of_node, "planes");
1041         if (!manager->node) {
1042                 DRM_ERROR("failed to get a planes node\n");
1043                 return ERR_PTR(-EINVAL);
1044         }
1045
1046         /* check the base pixel format of plane manager */
1047         ret = of_property_read_string(manager->node, "xlnx,pixel-format",
1048                                       &format);
1049         if (ret < 0) {
1050                 DRM_ERROR("failed to get a plane manager format\n");
1051                 return ERR_PTR(ret);
1052         }
1053
1054         ret = xilinx_drm_format_by_name(format, &manager->format);
1055         if (ret < 0) {
1056                 DRM_ERROR("invalid plane manager format\n");
1057                 return ERR_PTR(ret);
1058         }
1059
1060         manager->drm = drm;
1061
1062         /* probe an OSD. proceed even if there's no OSD */
1063         sub_node = of_parse_phandle(dev->of_node, "xlnx,osd", 0);
1064         if (sub_node) {
1065                 manager->osd = xilinx_osd_probe(dev, sub_node);
1066                 of_node_put(sub_node);
1067                 if (IS_ERR(manager->osd)) {
1068                         of_node_put(manager->node);
1069                         DRM_ERROR("failed to probe an osd\n");
1070                         return ERR_CAST(manager->osd);
1071                 }
1072                 manager->default_alpha = OSD_MAX_ALPHA;
1073         }
1074
1075         manager->dp_sub = xilinx_drm_dp_sub_of_get(drm->dev->of_node);
1076         if (IS_ERR(manager->dp_sub)) {
1077                 DRM_DEBUG_KMS("failed to get a dp_sub\n");
1078                 return ERR_CAST(manager->dp_sub);
1079         } else if (manager->dp_sub) {
1080                 manager->default_alpha = XILINX_DRM_DP_SUB_MAX_ALPHA;
1081         }
1082
1083         ret = xilinx_drm_plane_init_manager(manager);
1084         if (ret) {
1085                 DRM_ERROR("failed to init a plane manager\n");
1086                 return ERR_PTR(ret);
1087         }
1088
1089         xilinx_drm_plane_create_property(manager);
1090
1091         return manager;
1092 }
1093
1094 void xilinx_drm_plane_remove_manager(struct xilinx_drm_plane_manager *manager)
1095 {
1096         xilinx_drm_dp_sub_put(manager->dp_sub);
1097         of_node_put(manager->node);
1098 }