2 * Xilinx DRM plane driver for Xilinx
4 * Copyright (C) 2013 Xilinx, Inc.
6 * Author: Hyun Woo Kwon <hyunk@xilinx.com>
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.
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.
19 #include <drm/drm_crtc.h>
20 #include <drm/drm_fb_cma_helper.h>
21 #include <drm/drm_gem_cma_helper.h>
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>
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"
35 #include "xilinx_cresample.h"
36 #include "xilinx_osd.h"
37 #include "xilinx_rgb2yuv.h"
39 #define MAX_NUM_SUB_PLANES 4
42 * struct xilinx_drm_plane_dma - Xilinx drm plane VDMA object
45 * @xt: dma interleaved configuration template
46 * @sgl: data chunk for dma_interleaved_template
47 * @is_active: flag if the DMA is active
49 struct xilinx_drm_plane_dma {
50 struct dma_chan *chan;
51 struct dma_interleaved_template xt;
52 struct data_chunk sgl[1];
57 * struct xilinx_drm_plane - Xilinx drm plane object
59 * @base: base drm plane object
61 * @dpms: current dpms level
62 * @zpos: user requested z-position value
63 * @prio: actual layer priority
65 * @alpha_enable: alpha enable value
66 * @primary: flag for primary plane
67 * @format: pixel format
69 * @rgb2yuv: rgb2yuv instance
70 * @cresample: cresample instance
71 * @osd_layer: osd layer
72 * @dp_layer: DisplayPort subsystem layer
73 * @manager: plane manager
75 struct xilinx_drm_plane {
76 struct drm_plane base;
82 unsigned int alpha_enable;
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;
96 * struct xilinx_drm_plane_manager - Xilinx drm plane manager object
99 * @node: plane device node
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
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;
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];
126 #define to_xilinx_plane(x) container_of(x, struct xilinx_drm_plane, base)
128 void xilinx_drm_plane_commit(struct drm_plane *base_plane)
130 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
131 struct dma_async_tx_descriptor *desc;
132 enum dma_ctrl_flags flags;
135 /* for xilinx video framebuffer dma, if used */
136 xilinx_xdma_drm_config(plane->dma[0].chan, plane->format);
138 DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
140 for (i = 0; i < MAX_NUM_SUB_PLANES; i++) {
141 struct xilinx_drm_plane_dma *dma = &plane->dma[i];
143 if (dma->chan && dma->is_active) {
144 flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
145 desc = dmaengine_prep_interleaved_dma(dma->chan,
149 DRM_ERROR("failed to prepare DMA descriptor\n");
153 dmaengine_submit(desc);
155 dma_async_issue_pending(dma->chan);
161 void xilinx_drm_plane_dpms(struct drm_plane *base_plane, int dpms)
163 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
164 struct xilinx_drm_plane_manager *manager = plane->manager;
167 DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
168 DRM_DEBUG_KMS("dpms: %d -> %d\n", plane->dpms, dpms);
170 if (plane->dpms == 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,
183 xilinx_drm_dp_sub_layer_enable(manager->dp_sub,
188 xilinx_rgb2yuv_enable(plane->rgb2yuv);
190 if (plane->cresample)
191 xilinx_cresample_enable(plane->cresample);
195 xilinx_osd_disable_rue(manager->osd);
197 xilinx_osd_layer_set_priority(plane->osd_layer,
199 xilinx_osd_layer_enable_alpha(plane->osd_layer,
200 plane->alpha_enable);
201 xilinx_osd_layer_set_alpha(plane->osd_layer,
203 xilinx_osd_layer_enable(plane->osd_layer);
205 xilinx_osd_enable_rue(manager->osd);
208 xilinx_drm_plane_commit(base_plane);
211 /* disable/reset osd */
213 xilinx_osd_disable_rue(manager->osd);
215 xilinx_osd_layer_set_dimension(plane->osd_layer,
217 xilinx_osd_layer_disable(plane->osd_layer);
219 xilinx_osd_enable_rue(manager->osd);
222 if (plane->cresample) {
223 xilinx_cresample_disable(plane->cresample);
224 xilinx_cresample_reset(plane->cresample);
227 if (plane->rgb2yuv) {
228 xilinx_rgb2yuv_disable(plane->rgb2yuv);
229 xilinx_rgb2yuv_reset(plane->rgb2yuv);
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);
239 xilinx_drm_dp_sub_layer_disable(manager->dp_sub,
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)
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;
259 unsigned int hsub, vsub, i;
261 DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
263 /* configure cresample */
264 if (plane->cresample)
265 xilinx_cresample_configure(plane->cresample, crtc_w, crtc_h);
267 /* configure rgb2yuv */
269 xilinx_rgb2yuv_configure(plane->rgb2yuv, crtc_w, crtc_h);
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);
277 DRM_ERROR("Unsupported framebuffer format %s\n",
278 drm_get_format_name(info->format, &format_name));
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];
291 cpp = xilinx_drm_format_bpp(fb->format->format) >> 3;
293 obj = xilinx_drm_fb_get_gem_obj(fb, i);
295 DRM_ERROR("failed to get a gem obj for fb\n");
299 plane->dma[i].xt.numf = height;
300 plane->dma[i].sgl[0].size = drm_format_plane_width_bytes(info,
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;
316 for (; i < MAX_NUM_SUB_PLANES; i++)
317 plane->dma[i].is_active = false;
319 /* set OSD dimensions */
320 if (plane->manager->osd) {
321 xilinx_osd_disable_rue(plane->manager->osd);
323 xilinx_osd_layer_set_dimension(plane->osd_layer, crtc_x, crtc_y,
326 xilinx_osd_enable_rue(plane->manager->osd);
329 if (plane->manager->dp_sub) {
332 ret = xilinx_drm_dp_sub_layer_check_size(plane->manager->dp_sub,
338 ret = xilinx_drm_dp_sub_layer_set_fmt(plane->manager->dp_sub,
342 DRM_ERROR("failed to set dp_sub layer fmt\n");
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)
360 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
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);
368 DRM_ERROR("failed to mode-set a plane\n");
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);
376 xilinx_drm_plane_commit(base_plane);
381 /* disable a plane */
382 static int xilinx_drm_plane_disable(struct drm_plane *base_plane,
383 struct drm_modeset_acquire_ctx *ctx)
385 xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_OFF);
390 /* destroy a plane */
391 static void xilinx_drm_plane_destroy(struct drm_plane *base_plane)
393 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
396 xilinx_drm_plane_dpms(base_plane, DRM_MODE_DPMS_OFF);
398 plane->manager->planes[plane->id] = NULL;
400 drm_plane_cleanup(base_plane);
402 for (i = 0; i < MAX_NUM_SUB_PLANES; i++)
403 if (plane->dma[i].chan)
404 dma_release_channel(plane->dma[i].chan);
406 if (plane->manager->osd) {
407 xilinx_osd_layer_disable(plane->osd_layer);
408 xilinx_osd_layer_put(plane->osd_layer);
411 if (plane->manager->dp_sub) {
412 xilinx_drm_dp_sub_layer_disable(plane->manager->dp_sub,
414 xilinx_drm_dp_sub_layer_put(plane->manager->dp_sub,
420 * xilinx_drm_plane_update_prio - Configure plane priorities based on zpos
421 * @manager: the plane manager
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.
431 xilinx_drm_plane_update_prio(struct xilinx_drm_plane_manager *manager)
433 struct xilinx_drm_plane *planes[MAX_PLANES];
434 struct xilinx_drm_plane *plane;
437 /* sort planes by zpos */
438 for (i = 0; i < manager->num_planes; i++) {
439 plane = manager->planes[i];
441 for (j = i; j > 0; --j) {
442 if (planes[j - 1]->zpos <= plane->zpos)
444 planes[j] = planes[j - 1];
450 xilinx_osd_disable_rue(manager->osd);
452 /* remove duplicates by reassigning priority */
453 for (i = 0; i < manager->num_planes; i++) {
455 xilinx_osd_layer_set_priority(planes[i]->osd_layer,
459 xilinx_osd_enable_rue(manager->osd);
462 static void xilinx_drm_plane_set_zpos(struct drm_plane *base_plane,
465 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
466 struct xilinx_drm_plane_manager *manager = plane->manager;
470 for (i = 0; i < manager->num_planes; i++) {
471 if (manager->planes[i] != plane &&
472 manager->planes[i]->prio == zpos) {
481 xilinx_drm_plane_update_prio(manager);
484 xilinx_osd_layer_set_priority(plane->osd_layer, plane->prio);
488 static void xilinx_drm_plane_set_alpha(struct drm_plane *base_plane,
491 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
492 struct xilinx_drm_plane_manager *manager = plane->manager;
494 plane->alpha = alpha;
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);
502 static void xilinx_drm_plane_enable_alpha(struct drm_plane *base_plane,
505 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
506 struct xilinx_drm_plane_manager *manager = plane->manager;
508 plane->alpha_enable = enable;
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);
516 /* set property of a plane */
517 static int xilinx_drm_plane_set_property(struct drm_plane *base_plane,
518 struct drm_property *property,
521 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
522 struct xilinx_drm_plane_manager *manager = plane->manager;
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);
533 drm_object_property_set_value(&base_plane->base, property, val);
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,
545 /* get a plane max width */
546 int xilinx_drm_plane_get_max_width(struct drm_plane *base_plane)
548 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
550 return plane->manager->max_width;
553 /* check if format is supported */
554 bool xilinx_drm_plane_check_format(struct xilinx_drm_plane_manager *manager,
559 for (i = 0; i < MAX_PLANES; i++)
560 if (manager->planes[i] &&
561 (manager->planes[i]->format == format))
567 /* get the number of planes */
568 int xilinx_drm_plane_get_num_planes(struct xilinx_drm_plane_manager *manager)
570 return manager->num_planes;
574 * xilinx_drm_plane_restore - Restore the plane states
575 * @manager: the plane manager
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.
582 void xilinx_drm_plane_restore(struct xilinx_drm_plane_manager *manager)
584 struct xilinx_drm_plane *plane;
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.
592 for (i = 0; i < manager->num_planes; i++) {
593 plane = manager->planes[i];
595 plane->prio = plane->id;
596 plane->zpos = plane->id;
597 if (manager->zpos_prop)
598 drm_object_property_set_value(&plane->base.base,
602 plane->alpha = manager->default_alpha;
603 if (manager->alpha_prop)
604 drm_object_property_set_value(&plane->base.base,
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);
615 /* get the plane format */
616 u32 xilinx_drm_plane_get_format(struct drm_plane *base_plane)
618 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
620 return plane->format;
624 * xilinx_drm_plane_get_align - Get the alignment value for pitch
625 * @base_plane: Base drm plane object
627 * Get the alignment value for pitch from the dma device
629 * Return: The alignment value if successful, or the error code.
631 unsigned int xilinx_drm_plane_get_align(struct drm_plane *base_plane)
633 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
635 return 1 << plane->dma[0].chan->device->copy_align;
638 /* create plane properties */
640 xilinx_drm_plane_create_property(struct xilinx_drm_plane_manager *manager)
643 manager->zpos_prop = drm_property_create_range(manager->drm, 0,
644 "zpos", 0, manager->num_planes - 1);
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");
655 /* attach plane properties */
656 static void xilinx_drm_plane_attach_property(struct drm_plane *base_plane)
658 struct xilinx_drm_plane *plane = to_xilinx_plane(base_plane);
659 struct xilinx_drm_plane_manager *manager = plane->manager;
661 if (manager->zpos_prop)
662 drm_object_attach_property(&base_plane->base,
666 if (manager->alpha_prop) {
667 if (manager->dp_sub && !plane->primary)
670 drm_object_attach_property(&base_plane->base,
672 manager->default_alpha);
673 drm_object_attach_property(&base_plane->base,
674 manager->alpha_enable_prop, false);
677 plane->alpha_enable = true;
681 * xilinx_drm_plane_manager_dpms - Set DPMS for the Xilinx plane manager
682 * @manager: Xilinx plane manager object
683 * @dpms: requested DPMS
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().
688 void xilinx_drm_plane_manager_dpms(struct xilinx_drm_plane_manager *manager,
692 case DRM_MODE_DPMS_ON:
693 if (manager->dp_sub) {
694 xilinx_drm_dp_sub_set_bg_color(manager->dp_sub,
696 xilinx_drm_dp_sub_enable(manager->dp_sub);
700 xilinx_osd_disable_rue(manager->osd);
701 xilinx_osd_enable(manager->osd);
702 xilinx_osd_enable_rue(manager->osd);
708 xilinx_osd_reset(manager->osd);
711 xilinx_drm_dp_sub_disable(manager->dp_sub);
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
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().
726 void xilinx_drm_plane_manager_mode_set(struct xilinx_drm_plane_manager *manager,
727 unsigned int crtc_w, unsigned int crtc_h)
730 xilinx_osd_set_dimension(manager->osd, crtc_w, crtc_h);
734 static struct xilinx_drm_plane *
735 xilinx_drm_plane_create(struct xilinx_drm_plane_manager *manager,
736 unsigned int possible_crtcs, bool primary)
738 struct xilinx_drm_plane *plane;
739 struct device *dev = manager->drm->dev;
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;
752 unsigned int num_fmts = 0;
754 for (i = 0; i < manager->num_planes; i++)
755 if (!manager->planes[i])
758 if (i >= manager->num_planes) {
759 DRM_ERROR("failed to allocate plane\n");
760 return ERR_PTR(-ENODEV);
763 snprintf(plane_name, sizeof(plane_name), "plane%d", i);
764 plane_node = of_get_child_by_name(manager->node, plane_name);
766 DRM_ERROR("failed to find a plane node\n");
767 return ERR_PTR(-ENODEV);
770 plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL);
776 plane->primary = primary;
780 plane->alpha = manager->default_alpha;
781 plane->dpms = DRM_MODE_DPMS_OFF;
783 DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
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),
793 plane->dma[i].chan = of_dma_request_slave_channel(plane_node,
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;
806 DRM_ERROR("plane \"%s\" doesn't have any dma channels (dma-names)\n",
807 of_node_full_name(plane_node));
812 /* probe color space converter */
813 sub_node = of_parse_phandle(plane_node, "xlnx,rgb2yuv", i);
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);
823 /* rgb2yuv input format */
824 plane->format = DRM_FORMAT_XRGB8888;
826 /* rgb2yuv output format */
827 fmt_out = DRM_FORMAT_YUV444;
830 /* probe chroma resampler */
831 sub_node = of_parse_phandle(plane_node, "xlnx,cresample", i);
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);
841 /* cresample input format */
842 fmt = xilinx_cresample_get_input_format_name(plane->cresample);
843 ret = xilinx_drm_format_by_name(fmt, &fmt_in);
847 /* format sanity check */
848 if ((fmt_out != 0) && (fmt_out != fmt_in)) {
849 DRM_ERROR("input/output format mismatch\n");
854 if (plane->format == 0)
855 plane->format = fmt_in;
857 /* cresample output format */
858 fmt = xilinx_cresample_get_output_format_name(plane->cresample);
859 ret = xilinx_drm_format_by_name(fmt, &fmt_out);
864 /* create an OSD layer when OSD is available */
866 /* format sanity check */
867 if ((fmt_out != 0) && (fmt_out != manager->format)) {
868 DRM_ERROR("input/output format mismatch\n");
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;
882 if (plane->format == 0)
883 plane->format = manager->format;
886 if (manager->dp_sub) {
887 plane->dp_layer = xilinx_drm_dp_sub_layer_get(manager->dp_sub,
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;
897 ret = xilinx_drm_dp_sub_layer_set_fmt(manager->dp_sub,
901 DRM_ERROR("failed to set dp_sub layer fmt\n");
907 xilinx_drm_dp_sub_layer_get_fmt(manager->dp_sub,
909 xilinx_drm_dp_sub_layer_get_fmts(manager->dp_sub,
910 plane->dp_layer, &fmts,
914 /* If there's no IP other than VDMA, pick the manager's format */
915 if (plane->format == 0)
916 plane->format = manager->format;
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,
926 DRM_ERROR("failed to initialize plane\n");
929 plane->manager = manager;
930 manager->planes[plane->id] = plane;
932 xilinx_drm_plane_attach_property(&plane->base);
934 of_node_put(plane_node);
939 if (manager->dp_sub) {
940 xilinx_drm_dp_sub_layer_disable(manager->dp_sub,
942 xilinx_drm_dp_sub_layer_put(plane->manager->dp_sub,
946 xilinx_osd_layer_disable(plane->osd_layer);
947 xilinx_osd_layer_put(plane->osd_layer);
950 for (i = 0; i < MAX_NUM_SUB_PLANES; i++)
951 if (plane->dma[i].chan)
952 dma_release_channel(plane->dma[i].chan);
954 of_node_put(plane_node);
958 /* create a primary plane */
960 xilinx_drm_plane_create_primary(struct xilinx_drm_plane_manager *manager,
961 unsigned int possible_crtcs)
963 struct xilinx_drm_plane *plane;
965 plane = xilinx_drm_plane_create(manager, possible_crtcs, true);
967 DRM_ERROR("failed to allocate a primary plane\n");
968 return ERR_CAST(plane);
974 /* create extra planes */
975 int xilinx_drm_plane_create_planes(struct xilinx_drm_plane_manager *manager,
976 unsigned int possible_crtcs)
978 struct xilinx_drm_plane *plane;
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])
986 plane = xilinx_drm_plane_create(manager, possible_crtcs, false);
988 DRM_ERROR("failed to allocate a plane\n");
989 return PTR_ERR(plane);
992 manager->planes[i] = plane;
998 /* initialize a plane manager: num_planes, format, max_width */
1000 xilinx_drm_plane_init_manager(struct xilinx_drm_plane_manager *manager)
1002 unsigned int format;
1007 manager->num_planes = xilinx_osd_get_num_layers(manager->osd);
1008 manager->max_width = xilinx_osd_get_max_width(manager->osd);
1010 format = xilinx_osd_get_format(manager->osd);
1011 ret = xilinx_drm_format_by_code(format, &drm_format);
1012 if (drm_format != manager->format)
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;
1018 /* without osd, only one plane is supported */
1019 manager->num_planes = 1;
1020 manager->max_width = 4096;
1026 struct xilinx_drm_plane_manager *
1027 xilinx_drm_plane_probe_manager(struct drm_device *drm)
1029 struct xilinx_drm_plane_manager *manager;
1030 struct device *dev = drm->dev;
1031 struct device_node *sub_node;
1035 manager = devm_kzalloc(dev, sizeof(*manager), GFP_KERNEL);
1037 return ERR_PTR(-ENOMEM);
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);
1046 /* check the base pixel format of plane manager */
1047 ret = of_property_read_string(manager->node, "xlnx,pixel-format",
1050 DRM_ERROR("failed to get a plane manager format\n");
1051 return ERR_PTR(ret);
1054 ret = xilinx_drm_format_by_name(format, &manager->format);
1056 DRM_ERROR("invalid plane manager format\n");
1057 return ERR_PTR(ret);
1062 /* probe an OSD. proceed even if there's no OSD */
1063 sub_node = of_parse_phandle(dev->of_node, "xlnx,osd", 0);
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);
1072 manager->default_alpha = OSD_MAX_ALPHA;
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;
1083 ret = xilinx_drm_plane_init_manager(manager);
1085 DRM_ERROR("failed to init a plane manager\n");
1086 return ERR_PTR(ret);
1089 xilinx_drm_plane_create_property(manager);
1094 void xilinx_drm_plane_remove_manager(struct xilinx_drm_plane_manager *manager)
1096 xilinx_drm_dp_sub_put(manager->dp_sub);
1097 of_node_put(manager->node);