xref: /openbmc/linux/drivers/gpu/drm/imx/dcss/dcss-plane.c (revision 41016fe1)
19021c317SLaurentiu Palcu // SPDX-License-Identifier: GPL-2.0
29021c317SLaurentiu Palcu /*
39021c317SLaurentiu Palcu  * Copyright 2019 NXP.
49021c317SLaurentiu Palcu  */
59021c317SLaurentiu Palcu 
69021c317SLaurentiu Palcu #include <drm/drm_atomic.h>
79021c317SLaurentiu Palcu #include <drm/drm_atomic_helper.h>
89021c317SLaurentiu Palcu #include <drm/drm_fb_cma_helper.h>
9820c1707SThomas Zimmermann #include <drm/drm_gem_atomic_helper.h>
109021c317SLaurentiu Palcu #include <drm/drm_gem_cma_helper.h>
119021c317SLaurentiu Palcu 
129021c317SLaurentiu Palcu #include "dcss-dev.h"
139021c317SLaurentiu Palcu #include "dcss-kms.h"
149021c317SLaurentiu Palcu 
159021c317SLaurentiu Palcu static const u32 dcss_common_formats[] = {
169021c317SLaurentiu Palcu 	/* RGB */
179021c317SLaurentiu Palcu 	DRM_FORMAT_ARGB8888,
189021c317SLaurentiu Palcu 	DRM_FORMAT_XRGB8888,
199021c317SLaurentiu Palcu 	DRM_FORMAT_ABGR8888,
209021c317SLaurentiu Palcu 	DRM_FORMAT_XBGR8888,
219021c317SLaurentiu Palcu 	DRM_FORMAT_RGBA8888,
229021c317SLaurentiu Palcu 	DRM_FORMAT_RGBX8888,
239021c317SLaurentiu Palcu 	DRM_FORMAT_BGRA8888,
249021c317SLaurentiu Palcu 	DRM_FORMAT_BGRX8888,
259021c317SLaurentiu Palcu 	DRM_FORMAT_XRGB2101010,
269021c317SLaurentiu Palcu 	DRM_FORMAT_XBGR2101010,
279021c317SLaurentiu Palcu 	DRM_FORMAT_RGBX1010102,
289021c317SLaurentiu Palcu 	DRM_FORMAT_BGRX1010102,
299021c317SLaurentiu Palcu 	DRM_FORMAT_ARGB2101010,
309021c317SLaurentiu Palcu 	DRM_FORMAT_ABGR2101010,
319021c317SLaurentiu Palcu 	DRM_FORMAT_RGBA1010102,
329021c317SLaurentiu Palcu 	DRM_FORMAT_BGRA1010102,
339021c317SLaurentiu Palcu };
349021c317SLaurentiu Palcu 
359021c317SLaurentiu Palcu static const u64 dcss_video_format_modifiers[] = {
369021c317SLaurentiu Palcu 	DRM_FORMAT_MOD_LINEAR,
379021c317SLaurentiu Palcu 	DRM_FORMAT_MOD_INVALID,
389021c317SLaurentiu Palcu };
399021c317SLaurentiu Palcu 
409021c317SLaurentiu Palcu static const u64 dcss_graphics_format_modifiers[] = {
419021c317SLaurentiu Palcu 	DRM_FORMAT_MOD_VIVANTE_TILED,
429021c317SLaurentiu Palcu 	DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
439021c317SLaurentiu Palcu 	DRM_FORMAT_MOD_LINEAR,
449021c317SLaurentiu Palcu 	DRM_FORMAT_MOD_INVALID,
459021c317SLaurentiu Palcu };
469021c317SLaurentiu Palcu 
479021c317SLaurentiu Palcu static inline struct dcss_plane *to_dcss_plane(struct drm_plane *p)
489021c317SLaurentiu Palcu {
499021c317SLaurentiu Palcu 	return container_of(p, struct dcss_plane, base);
509021c317SLaurentiu Palcu }
519021c317SLaurentiu Palcu 
529021c317SLaurentiu Palcu static inline bool dcss_plane_fb_is_linear(const struct drm_framebuffer *fb)
539021c317SLaurentiu Palcu {
549021c317SLaurentiu Palcu 	return ((fb->flags & DRM_MODE_FB_MODIFIERS) == 0) ||
559021c317SLaurentiu Palcu 	       ((fb->flags & DRM_MODE_FB_MODIFIERS) != 0 &&
569021c317SLaurentiu Palcu 		fb->modifier == DRM_FORMAT_MOD_LINEAR);
579021c317SLaurentiu Palcu }
589021c317SLaurentiu Palcu 
599021c317SLaurentiu Palcu static void dcss_plane_destroy(struct drm_plane *plane)
609021c317SLaurentiu Palcu {
619021c317SLaurentiu Palcu 	struct dcss_plane *dcss_plane = container_of(plane, struct dcss_plane,
629021c317SLaurentiu Palcu 						     base);
639021c317SLaurentiu Palcu 
649021c317SLaurentiu Palcu 	drm_plane_cleanup(plane);
659021c317SLaurentiu Palcu 	kfree(dcss_plane);
669021c317SLaurentiu Palcu }
679021c317SLaurentiu Palcu 
689021c317SLaurentiu Palcu static bool dcss_plane_format_mod_supported(struct drm_plane *plane,
699021c317SLaurentiu Palcu 					    u32 format,
709021c317SLaurentiu Palcu 					    u64 modifier)
719021c317SLaurentiu Palcu {
729021c317SLaurentiu Palcu 	switch (plane->type) {
739021c317SLaurentiu Palcu 	case DRM_PLANE_TYPE_PRIMARY:
749021c317SLaurentiu Palcu 		switch (format) {
759021c317SLaurentiu Palcu 		case DRM_FORMAT_ARGB8888:
769021c317SLaurentiu Palcu 		case DRM_FORMAT_XRGB8888:
779021c317SLaurentiu Palcu 		case DRM_FORMAT_ARGB2101010:
789021c317SLaurentiu Palcu 			return modifier == DRM_FORMAT_MOD_LINEAR ||
799021c317SLaurentiu Palcu 			       modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
809021c317SLaurentiu Palcu 			       modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED;
819021c317SLaurentiu Palcu 		default:
829021c317SLaurentiu Palcu 			return modifier == DRM_FORMAT_MOD_LINEAR;
839021c317SLaurentiu Palcu 		}
849021c317SLaurentiu Palcu 		break;
859021c317SLaurentiu Palcu 	case DRM_PLANE_TYPE_OVERLAY:
869021c317SLaurentiu Palcu 		return modifier == DRM_FORMAT_MOD_LINEAR;
879021c317SLaurentiu Palcu 	default:
889021c317SLaurentiu Palcu 		return false;
899021c317SLaurentiu Palcu 	}
909021c317SLaurentiu Palcu }
919021c317SLaurentiu Palcu 
929021c317SLaurentiu Palcu static const struct drm_plane_funcs dcss_plane_funcs = {
939021c317SLaurentiu Palcu 	.update_plane		= drm_atomic_helper_update_plane,
949021c317SLaurentiu Palcu 	.disable_plane		= drm_atomic_helper_disable_plane,
959021c317SLaurentiu Palcu 	.destroy		= dcss_plane_destroy,
969021c317SLaurentiu Palcu 	.reset			= drm_atomic_helper_plane_reset,
979021c317SLaurentiu Palcu 	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
989021c317SLaurentiu Palcu 	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
999021c317SLaurentiu Palcu 	.format_mod_supported	= dcss_plane_format_mod_supported,
1009021c317SLaurentiu Palcu };
1019021c317SLaurentiu Palcu 
1029021c317SLaurentiu Palcu static bool dcss_plane_can_rotate(const struct drm_format_info *format,
1039021c317SLaurentiu Palcu 				  bool mod_present, u64 modifier,
1049021c317SLaurentiu Palcu 				  unsigned int rotation)
1059021c317SLaurentiu Palcu {
106594486b5SLaurentiu Palcu 	bool linear_format = !mod_present || modifier == DRM_FORMAT_MOD_LINEAR;
1079021c317SLaurentiu Palcu 	u32 supported_rotation = DRM_MODE_ROTATE_0;
1089021c317SLaurentiu Palcu 
1099021c317SLaurentiu Palcu 	if (!format->is_yuv && linear_format)
1109021c317SLaurentiu Palcu 		supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
1119021c317SLaurentiu Palcu 				     DRM_MODE_REFLECT_MASK;
1129021c317SLaurentiu Palcu 	else if (!format->is_yuv &&
11359cb403fSLaurentiu Palcu 		 (modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
11459cb403fSLaurentiu Palcu 		  modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED))
1159021c317SLaurentiu Palcu 		supported_rotation = DRM_MODE_ROTATE_MASK |
1169021c317SLaurentiu Palcu 				     DRM_MODE_REFLECT_MASK;
1179021c317SLaurentiu Palcu 	else if (format->is_yuv && linear_format &&
1189021c317SLaurentiu Palcu 		 (format->format == DRM_FORMAT_NV12 ||
1199021c317SLaurentiu Palcu 		  format->format == DRM_FORMAT_NV21))
1209021c317SLaurentiu Palcu 		supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
1219021c317SLaurentiu Palcu 				     DRM_MODE_REFLECT_MASK;
1229021c317SLaurentiu Palcu 
1239021c317SLaurentiu Palcu 	return !!(rotation & supported_rotation);
1249021c317SLaurentiu Palcu }
1259021c317SLaurentiu Palcu 
1269021c317SLaurentiu Palcu static bool dcss_plane_is_source_size_allowed(u16 src_w, u16 src_h, u32 pix_fmt)
1279021c317SLaurentiu Palcu {
1289021c317SLaurentiu Palcu 	if (src_w < 64 &&
1299021c317SLaurentiu Palcu 	    (pix_fmt == DRM_FORMAT_NV12 || pix_fmt == DRM_FORMAT_NV21))
1309021c317SLaurentiu Palcu 		return false;
1319021c317SLaurentiu Palcu 	else if (src_w < 32 &&
1329021c317SLaurentiu Palcu 		 (pix_fmt == DRM_FORMAT_UYVY || pix_fmt == DRM_FORMAT_VYUY ||
1339021c317SLaurentiu Palcu 		  pix_fmt == DRM_FORMAT_YUYV || pix_fmt == DRM_FORMAT_YVYU))
1349021c317SLaurentiu Palcu 		return false;
1359021c317SLaurentiu Palcu 
1369021c317SLaurentiu Palcu 	return src_w >= 16 && src_h >= 8;
1379021c317SLaurentiu Palcu }
1389021c317SLaurentiu Palcu 
1399021c317SLaurentiu Palcu static int dcss_plane_atomic_check(struct drm_plane *plane,
1407c11b99aSMaxime Ripard 				   struct drm_atomic_state *state)
1419021c317SLaurentiu Palcu {
1427c11b99aSMaxime Ripard 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
1437c11b99aSMaxime Ripard 										 plane);
1449021c317SLaurentiu Palcu 	struct dcss_plane *dcss_plane = to_dcss_plane(plane);
1459021c317SLaurentiu Palcu 	struct dcss_dev *dcss = plane->dev->dev_private;
146ba5c1649SMaxime Ripard 	struct drm_framebuffer *fb = new_plane_state->fb;
1479021c317SLaurentiu Palcu 	bool is_primary_plane = plane->type == DRM_PLANE_TYPE_PRIMARY;
1489021c317SLaurentiu Palcu 	struct drm_gem_cma_object *cma_obj;
1499021c317SLaurentiu Palcu 	struct drm_crtc_state *crtc_state;
1509021c317SLaurentiu Palcu 	int hdisplay, vdisplay;
1519021c317SLaurentiu Palcu 	int min, max;
1529021c317SLaurentiu Palcu 	int ret;
1539021c317SLaurentiu Palcu 
154ba5c1649SMaxime Ripard 	if (!fb || !new_plane_state->crtc)
1559021c317SLaurentiu Palcu 		return 0;
1569021c317SLaurentiu Palcu 
1579021c317SLaurentiu Palcu 	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
1589021c317SLaurentiu Palcu 	WARN_ON(!cma_obj);
1599021c317SLaurentiu Palcu 
160dec92020SMaxime Ripard 	crtc_state = drm_atomic_get_existing_crtc_state(state,
161ba5c1649SMaxime Ripard 							new_plane_state->crtc);
1629021c317SLaurentiu Palcu 
1639021c317SLaurentiu Palcu 	hdisplay = crtc_state->adjusted_mode.hdisplay;
1649021c317SLaurentiu Palcu 	vdisplay = crtc_state->adjusted_mode.vdisplay;
1659021c317SLaurentiu Palcu 
166ba5c1649SMaxime Ripard 	if (!dcss_plane_is_source_size_allowed(new_plane_state->src_w >> 16,
167ba5c1649SMaxime Ripard 					       new_plane_state->src_h >> 16,
1689021c317SLaurentiu Palcu 					       fb->format->format)) {
1699021c317SLaurentiu Palcu 		DRM_DEBUG_KMS("Source plane size is not allowed!\n");
1709021c317SLaurentiu Palcu 		return -EINVAL;
1719021c317SLaurentiu Palcu 	}
1729021c317SLaurentiu Palcu 
1739021c317SLaurentiu Palcu 	dcss_scaler_get_min_max_ratios(dcss->scaler, dcss_plane->ch_num,
1749021c317SLaurentiu Palcu 				       &min, &max);
1759021c317SLaurentiu Palcu 
176ba5c1649SMaxime Ripard 	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
1779021c317SLaurentiu Palcu 						  min, max, !is_primary_plane,
1789021c317SLaurentiu Palcu 						  false);
1799021c317SLaurentiu Palcu 	if (ret)
1809021c317SLaurentiu Palcu 		return ret;
1819021c317SLaurentiu Palcu 
182ba5c1649SMaxime Ripard 	if (!new_plane_state->visible)
1839021c317SLaurentiu Palcu 		return 0;
1849021c317SLaurentiu Palcu 
1859021c317SLaurentiu Palcu 	if (!dcss_plane_can_rotate(fb->format,
1869021c317SLaurentiu Palcu 				   !!(fb->flags & DRM_MODE_FB_MODIFIERS),
1879021c317SLaurentiu Palcu 				   fb->modifier,
188ba5c1649SMaxime Ripard 				   new_plane_state->rotation)) {
1899021c317SLaurentiu Palcu 		DRM_DEBUG_KMS("requested rotation is not allowed!\n");
1909021c317SLaurentiu Palcu 		return -EINVAL;
1919021c317SLaurentiu Palcu 	}
1929021c317SLaurentiu Palcu 
193ba5c1649SMaxime Ripard 	if ((new_plane_state->crtc_x < 0 || new_plane_state->crtc_y < 0 ||
194ba5c1649SMaxime Ripard 	     new_plane_state->crtc_x + new_plane_state->crtc_w > hdisplay ||
195ba5c1649SMaxime Ripard 	     new_plane_state->crtc_y + new_plane_state->crtc_h > vdisplay) &&
1969021c317SLaurentiu Palcu 	    !dcss_plane_fb_is_linear(fb)) {
1979021c317SLaurentiu Palcu 		DRM_DEBUG_KMS("requested cropping operation is not allowed!\n");
1989021c317SLaurentiu Palcu 		return -EINVAL;
1999021c317SLaurentiu Palcu 	}
2009021c317SLaurentiu Palcu 
2019021c317SLaurentiu Palcu 	if ((fb->flags & DRM_MODE_FB_MODIFIERS) &&
2029021c317SLaurentiu Palcu 	    !plane->funcs->format_mod_supported(plane,
2039021c317SLaurentiu Palcu 				fb->format->format,
2049021c317SLaurentiu Palcu 				fb->modifier)) {
2059021c317SLaurentiu Palcu 		DRM_DEBUG_KMS("Invalid modifier: %llx", fb->modifier);
2069021c317SLaurentiu Palcu 		return -EINVAL;
2079021c317SLaurentiu Palcu 	}
2089021c317SLaurentiu Palcu 
2099021c317SLaurentiu Palcu 	return 0;
2109021c317SLaurentiu Palcu }
2119021c317SLaurentiu Palcu 
2129021c317SLaurentiu Palcu static void dcss_plane_atomic_set_base(struct dcss_plane *dcss_plane)
2139021c317SLaurentiu Palcu {
2149021c317SLaurentiu Palcu 	struct drm_plane *plane = &dcss_plane->base;
2159021c317SLaurentiu Palcu 	struct drm_plane_state *state = plane->state;
2169021c317SLaurentiu Palcu 	struct dcss_dev *dcss = plane->dev->dev_private;
2179021c317SLaurentiu Palcu 	struct drm_framebuffer *fb = state->fb;
2189021c317SLaurentiu Palcu 	const struct drm_format_info *format = fb->format;
2199021c317SLaurentiu Palcu 	struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
2209021c317SLaurentiu Palcu 	unsigned long p1_ba = 0, p2_ba = 0;
2219021c317SLaurentiu Palcu 
2229021c317SLaurentiu Palcu 	if (!format->is_yuv ||
2239021c317SLaurentiu Palcu 	    format->format == DRM_FORMAT_NV12 ||
2249021c317SLaurentiu Palcu 	    format->format == DRM_FORMAT_NV21)
2259021c317SLaurentiu Palcu 		p1_ba = cma_obj->paddr + fb->offsets[0] +
2269021c317SLaurentiu Palcu 			fb->pitches[0] * (state->src.y1 >> 16) +
2279021c317SLaurentiu Palcu 			format->char_per_block[0] * (state->src.x1 >> 16);
2289021c317SLaurentiu Palcu 	else if (format->format == DRM_FORMAT_UYVY ||
2299021c317SLaurentiu Palcu 		 format->format == DRM_FORMAT_VYUY ||
2309021c317SLaurentiu Palcu 		 format->format == DRM_FORMAT_YUYV ||
2319021c317SLaurentiu Palcu 		 format->format == DRM_FORMAT_YVYU)
2329021c317SLaurentiu Palcu 		p1_ba = cma_obj->paddr + fb->offsets[0] +
2339021c317SLaurentiu Palcu 			fb->pitches[0] * (state->src.y1 >> 16) +
2349021c317SLaurentiu Palcu 			2 * format->char_per_block[0] * (state->src.x1 >> 17);
2359021c317SLaurentiu Palcu 
2369021c317SLaurentiu Palcu 	if (format->format == DRM_FORMAT_NV12 ||
2379021c317SLaurentiu Palcu 	    format->format == DRM_FORMAT_NV21)
2389021c317SLaurentiu Palcu 		p2_ba = cma_obj->paddr + fb->offsets[1] +
2399021c317SLaurentiu Palcu 			(((fb->pitches[1] >> 1) * (state->src.y1 >> 17) +
2409021c317SLaurentiu Palcu 			(state->src.x1 >> 17)) << 1);
2419021c317SLaurentiu Palcu 
2429021c317SLaurentiu Palcu 	dcss_dpr_addr_set(dcss->dpr, dcss_plane->ch_num, p1_ba, p2_ba,
2439021c317SLaurentiu Palcu 			  fb->pitches[0]);
2449021c317SLaurentiu Palcu }
2459021c317SLaurentiu Palcu 
2469021c317SLaurentiu Palcu static bool dcss_plane_needs_setup(struct drm_plane_state *state,
2479021c317SLaurentiu Palcu 				   struct drm_plane_state *old_state)
2489021c317SLaurentiu Palcu {
2499021c317SLaurentiu Palcu 	struct drm_framebuffer *fb = state->fb;
2509021c317SLaurentiu Palcu 	struct drm_framebuffer *old_fb = old_state->fb;
2519021c317SLaurentiu Palcu 
2529021c317SLaurentiu Palcu 	return state->crtc_x != old_state->crtc_x ||
2539021c317SLaurentiu Palcu 	       state->crtc_y != old_state->crtc_y ||
2549021c317SLaurentiu Palcu 	       state->crtc_w != old_state->crtc_w ||
2559021c317SLaurentiu Palcu 	       state->crtc_h != old_state->crtc_h ||
2569021c317SLaurentiu Palcu 	       state->src_x  != old_state->src_x  ||
2579021c317SLaurentiu Palcu 	       state->src_y  != old_state->src_y  ||
2589021c317SLaurentiu Palcu 	       state->src_w  != old_state->src_w  ||
2599021c317SLaurentiu Palcu 	       state->src_h  != old_state->src_h  ||
2609021c317SLaurentiu Palcu 	       fb->format->format != old_fb->format->format ||
2619021c317SLaurentiu Palcu 	       fb->modifier  != old_fb->modifier ||
26205faf155SLaurentiu Palcu 	       state->rotation != old_state->rotation ||
26305faf155SLaurentiu Palcu 	       state->scaling_filter != old_state->scaling_filter;
2649021c317SLaurentiu Palcu }
2659021c317SLaurentiu Palcu 
2669021c317SLaurentiu Palcu static void dcss_plane_atomic_update(struct drm_plane *plane,
2679021c317SLaurentiu Palcu 				     struct drm_plane_state *old_state)
2689021c317SLaurentiu Palcu {
269*41016fe1SMaxime Ripard 	struct drm_plane_state *new_state = plane->state;
2709021c317SLaurentiu Palcu 	struct dcss_plane *dcss_plane = to_dcss_plane(plane);
2719021c317SLaurentiu Palcu 	struct dcss_dev *dcss = plane->dev->dev_private;
272*41016fe1SMaxime Ripard 	struct drm_framebuffer *fb = new_state->fb;
2739021c317SLaurentiu Palcu 	struct drm_crtc_state *crtc_state;
2749021c317SLaurentiu Palcu 	bool modifiers_present;
2759021c317SLaurentiu Palcu 	u32 src_w, src_h, dst_w, dst_h;
2769021c317SLaurentiu Palcu 	struct drm_rect src, dst;
2779021c317SLaurentiu Palcu 	bool enable = true;
27859cb403fSLaurentiu Palcu 	bool is_rotation_90_or_270;
2799021c317SLaurentiu Palcu 
280*41016fe1SMaxime Ripard 	if (!fb || !new_state->crtc || !new_state->visible)
2819021c317SLaurentiu Palcu 		return;
2829021c317SLaurentiu Palcu 
283*41016fe1SMaxime Ripard 	crtc_state = new_state->crtc->state;
2849021c317SLaurentiu Palcu 	modifiers_present = !!(fb->flags & DRM_MODE_FB_MODIFIERS);
2859021c317SLaurentiu Palcu 
2869021c317SLaurentiu Palcu 	if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state) &&
287*41016fe1SMaxime Ripard 	    !dcss_plane_needs_setup(new_state, old_state)) {
2889021c317SLaurentiu Palcu 		dcss_plane_atomic_set_base(dcss_plane);
2899021c317SLaurentiu Palcu 		return;
2909021c317SLaurentiu Palcu 	}
2919021c317SLaurentiu Palcu 
2929021c317SLaurentiu Palcu 	src = plane->state->src;
2939021c317SLaurentiu Palcu 	dst = plane->state->dst;
2949021c317SLaurentiu Palcu 
2959021c317SLaurentiu Palcu 	/*
2969021c317SLaurentiu Palcu 	 * The width and height after clipping.
2979021c317SLaurentiu Palcu 	 */
2989021c317SLaurentiu Palcu 	src_w = drm_rect_width(&src) >> 16;
2999021c317SLaurentiu Palcu 	src_h = drm_rect_height(&src) >> 16;
3009021c317SLaurentiu Palcu 	dst_w = drm_rect_width(&dst);
3019021c317SLaurentiu Palcu 	dst_h = drm_rect_height(&dst);
3029021c317SLaurentiu Palcu 
3039021c317SLaurentiu Palcu 	if (plane->type == DRM_PLANE_TYPE_OVERLAY &&
3049021c317SLaurentiu Palcu 	    modifiers_present && fb->modifier == DRM_FORMAT_MOD_LINEAR)
3059021c317SLaurentiu Palcu 		modifiers_present = false;
3069021c317SLaurentiu Palcu 
307*41016fe1SMaxime Ripard 	dcss_dpr_format_set(dcss->dpr, dcss_plane->ch_num,
308*41016fe1SMaxime Ripard 			    new_state->fb->format,
3099021c317SLaurentiu Palcu 			    modifiers_present ? fb->modifier :
3109021c317SLaurentiu Palcu 						DRM_FORMAT_MOD_LINEAR);
3119021c317SLaurentiu Palcu 	dcss_dpr_set_res(dcss->dpr, dcss_plane->ch_num, src_w, src_h);
3129021c317SLaurentiu Palcu 	dcss_dpr_set_rotation(dcss->dpr, dcss_plane->ch_num,
313*41016fe1SMaxime Ripard 			      new_state->rotation);
3149021c317SLaurentiu Palcu 
3159021c317SLaurentiu Palcu 	dcss_plane_atomic_set_base(dcss_plane);
3169021c317SLaurentiu Palcu 
317*41016fe1SMaxime Ripard 	is_rotation_90_or_270 = new_state->rotation & (DRM_MODE_ROTATE_90 |
31859cb403fSLaurentiu Palcu 						   DRM_MODE_ROTATE_270);
31959cb403fSLaurentiu Palcu 
32005faf155SLaurentiu Palcu 	dcss_scaler_set_filter(dcss->scaler, dcss_plane->ch_num,
321*41016fe1SMaxime Ripard 			       new_state->scaling_filter);
32205faf155SLaurentiu Palcu 
3239021c317SLaurentiu Palcu 	dcss_scaler_setup(dcss->scaler, dcss_plane->ch_num,
324*41016fe1SMaxime Ripard 			  new_state->fb->format,
32559cb403fSLaurentiu Palcu 			  is_rotation_90_or_270 ? src_h : src_w,
32659cb403fSLaurentiu Palcu 			  is_rotation_90_or_270 ? src_w : src_h,
3279021c317SLaurentiu Palcu 			  dst_w, dst_h,
3289021c317SLaurentiu Palcu 			  drm_mode_vrefresh(&crtc_state->mode));
3299021c317SLaurentiu Palcu 
3309021c317SLaurentiu Palcu 	dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
3319021c317SLaurentiu Palcu 			       dst.x1, dst.y1, dst_w, dst_h);
3329021c317SLaurentiu Palcu 	dcss_dtg_plane_alpha_set(dcss->dtg, dcss_plane->ch_num,
333*41016fe1SMaxime Ripard 				 fb->format, new_state->alpha >> 8);
3349021c317SLaurentiu Palcu 
335*41016fe1SMaxime Ripard 	if (!dcss_plane->ch_num && (new_state->alpha >> 8) == 0)
3369021c317SLaurentiu Palcu 		enable = false;
3379021c317SLaurentiu Palcu 
3389021c317SLaurentiu Palcu 	dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, enable);
3399021c317SLaurentiu Palcu 	dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, enable);
3409021c317SLaurentiu Palcu 
3419021c317SLaurentiu Palcu 	if (!enable)
3429021c317SLaurentiu Palcu 		dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
3439021c317SLaurentiu Palcu 				       0, 0, 0, 0);
3449021c317SLaurentiu Palcu 
3459021c317SLaurentiu Palcu 	dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, enable);
3469021c317SLaurentiu Palcu }
3479021c317SLaurentiu Palcu 
3489021c317SLaurentiu Palcu static void dcss_plane_atomic_disable(struct drm_plane *plane,
3499021c317SLaurentiu Palcu 				      struct drm_plane_state *old_state)
3509021c317SLaurentiu Palcu {
3519021c317SLaurentiu Palcu 	struct dcss_plane *dcss_plane = to_dcss_plane(plane);
3529021c317SLaurentiu Palcu 	struct dcss_dev *dcss = plane->dev->dev_private;
3539021c317SLaurentiu Palcu 
3549021c317SLaurentiu Palcu 	dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, false);
3559021c317SLaurentiu Palcu 	dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, false);
3569021c317SLaurentiu Palcu 	dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num, 0, 0, 0, 0);
3579021c317SLaurentiu Palcu 	dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, false);
3589021c317SLaurentiu Palcu }
3599021c317SLaurentiu Palcu 
3609021c317SLaurentiu Palcu static const struct drm_plane_helper_funcs dcss_plane_helper_funcs = {
361820c1707SThomas Zimmermann 	.prepare_fb = drm_gem_plane_helper_prepare_fb,
3629021c317SLaurentiu Palcu 	.atomic_check = dcss_plane_atomic_check,
3639021c317SLaurentiu Palcu 	.atomic_update = dcss_plane_atomic_update,
3649021c317SLaurentiu Palcu 	.atomic_disable = dcss_plane_atomic_disable,
3659021c317SLaurentiu Palcu };
3669021c317SLaurentiu Palcu 
3679021c317SLaurentiu Palcu struct dcss_plane *dcss_plane_init(struct drm_device *drm,
3689021c317SLaurentiu Palcu 				   unsigned int possible_crtcs,
3699021c317SLaurentiu Palcu 				   enum drm_plane_type type,
3709021c317SLaurentiu Palcu 				   unsigned int zpos)
3719021c317SLaurentiu Palcu {
3729021c317SLaurentiu Palcu 	struct dcss_plane *dcss_plane;
3739021c317SLaurentiu Palcu 	const u64 *format_modifiers = dcss_video_format_modifiers;
3749021c317SLaurentiu Palcu 	int ret;
3759021c317SLaurentiu Palcu 
3769021c317SLaurentiu Palcu 	if (zpos > 2)
3779021c317SLaurentiu Palcu 		return ERR_PTR(-EINVAL);
3789021c317SLaurentiu Palcu 
3799021c317SLaurentiu Palcu 	dcss_plane = kzalloc(sizeof(*dcss_plane), GFP_KERNEL);
3809021c317SLaurentiu Palcu 	if (!dcss_plane) {
3819021c317SLaurentiu Palcu 		DRM_ERROR("failed to allocate plane\n");
3829021c317SLaurentiu Palcu 		return ERR_PTR(-ENOMEM);
3839021c317SLaurentiu Palcu 	}
3849021c317SLaurentiu Palcu 
3859021c317SLaurentiu Palcu 	if (type == DRM_PLANE_TYPE_PRIMARY)
3869021c317SLaurentiu Palcu 		format_modifiers = dcss_graphics_format_modifiers;
3879021c317SLaurentiu Palcu 
3889021c317SLaurentiu Palcu 	ret = drm_universal_plane_init(drm, &dcss_plane->base, possible_crtcs,
3899021c317SLaurentiu Palcu 				       &dcss_plane_funcs, dcss_common_formats,
3909021c317SLaurentiu Palcu 				       ARRAY_SIZE(dcss_common_formats),
3919021c317SLaurentiu Palcu 				       format_modifiers, type, NULL);
3929021c317SLaurentiu Palcu 	if (ret) {
3939021c317SLaurentiu Palcu 		DRM_ERROR("failed to initialize plane\n");
3949021c317SLaurentiu Palcu 		kfree(dcss_plane);
3959021c317SLaurentiu Palcu 		return ERR_PTR(ret);
3969021c317SLaurentiu Palcu 	}
3979021c317SLaurentiu Palcu 
3989021c317SLaurentiu Palcu 	drm_plane_helper_add(&dcss_plane->base, &dcss_plane_helper_funcs);
3999021c317SLaurentiu Palcu 
4009021c317SLaurentiu Palcu 	ret = drm_plane_create_zpos_immutable_property(&dcss_plane->base, zpos);
4019021c317SLaurentiu Palcu 	if (ret)
4029021c317SLaurentiu Palcu 		return ERR_PTR(ret);
4039021c317SLaurentiu Palcu 
40405faf155SLaurentiu Palcu 	drm_plane_create_scaling_filter_property(&dcss_plane->base,
40505faf155SLaurentiu Palcu 					BIT(DRM_SCALING_FILTER_DEFAULT) |
40605faf155SLaurentiu Palcu 					BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
40705faf155SLaurentiu Palcu 
4089021c317SLaurentiu Palcu 	drm_plane_create_rotation_property(&dcss_plane->base,
4099021c317SLaurentiu Palcu 					   DRM_MODE_ROTATE_0,
4109021c317SLaurentiu Palcu 					   DRM_MODE_ROTATE_0   |
4119021c317SLaurentiu Palcu 					   DRM_MODE_ROTATE_90  |
4129021c317SLaurentiu Palcu 					   DRM_MODE_ROTATE_180 |
4139021c317SLaurentiu Palcu 					   DRM_MODE_ROTATE_270 |
4149021c317SLaurentiu Palcu 					   DRM_MODE_REFLECT_X  |
4159021c317SLaurentiu Palcu 					   DRM_MODE_REFLECT_Y);
4169021c317SLaurentiu Palcu 
4179021c317SLaurentiu Palcu 	dcss_plane->ch_num = zpos;
4189021c317SLaurentiu Palcu 
4199021c317SLaurentiu Palcu 	return dcss_plane;
4209021c317SLaurentiu Palcu }
421