xref: /openbmc/linux/drivers/gpu/drm/imx/dcss/dcss-plane.c (revision 8c30eecc)
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>
890bb087fSVille Syrjälä #include <drm/drm_blend.h>
96bcfe8eaSDanilo Krummrich #include <drm/drm_fb_dma_helper.h>
10720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h>
11820c1707SThomas Zimmermann #include <drm/drm_gem_atomic_helper.h>
124a83c26aSDanilo Krummrich #include <drm/drm_gem_dma_helper.h>
139021c317SLaurentiu Palcu 
149021c317SLaurentiu Palcu #include "dcss-dev.h"
159021c317SLaurentiu Palcu #include "dcss-kms.h"
169021c317SLaurentiu Palcu 
179021c317SLaurentiu Palcu static const u32 dcss_common_formats[] = {
189021c317SLaurentiu Palcu 	/* RGB */
199021c317SLaurentiu Palcu 	DRM_FORMAT_ARGB8888,
209021c317SLaurentiu Palcu 	DRM_FORMAT_XRGB8888,
219021c317SLaurentiu Palcu 	DRM_FORMAT_ABGR8888,
229021c317SLaurentiu Palcu 	DRM_FORMAT_XBGR8888,
239021c317SLaurentiu Palcu 	DRM_FORMAT_RGBA8888,
249021c317SLaurentiu Palcu 	DRM_FORMAT_RGBX8888,
259021c317SLaurentiu Palcu 	DRM_FORMAT_BGRA8888,
269021c317SLaurentiu Palcu 	DRM_FORMAT_BGRX8888,
279021c317SLaurentiu Palcu 	DRM_FORMAT_XRGB2101010,
289021c317SLaurentiu Palcu 	DRM_FORMAT_XBGR2101010,
299021c317SLaurentiu Palcu 	DRM_FORMAT_RGBX1010102,
309021c317SLaurentiu Palcu 	DRM_FORMAT_BGRX1010102,
319021c317SLaurentiu Palcu 	DRM_FORMAT_ARGB2101010,
329021c317SLaurentiu Palcu 	DRM_FORMAT_ABGR2101010,
339021c317SLaurentiu Palcu 	DRM_FORMAT_RGBA1010102,
349021c317SLaurentiu Palcu 	DRM_FORMAT_BGRA1010102,
359021c317SLaurentiu Palcu };
369021c317SLaurentiu Palcu 
379021c317SLaurentiu Palcu static const u64 dcss_video_format_modifiers[] = {
389021c317SLaurentiu Palcu 	DRM_FORMAT_MOD_LINEAR,
399021c317SLaurentiu Palcu 	DRM_FORMAT_MOD_INVALID,
409021c317SLaurentiu Palcu };
419021c317SLaurentiu Palcu 
429021c317SLaurentiu Palcu static const u64 dcss_graphics_format_modifiers[] = {
439021c317SLaurentiu Palcu 	DRM_FORMAT_MOD_VIVANTE_TILED,
449021c317SLaurentiu Palcu 	DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
459021c317SLaurentiu Palcu 	DRM_FORMAT_MOD_LINEAR,
469021c317SLaurentiu Palcu 	DRM_FORMAT_MOD_INVALID,
479021c317SLaurentiu Palcu };
489021c317SLaurentiu Palcu 
to_dcss_plane(struct drm_plane * p)499021c317SLaurentiu Palcu static inline struct dcss_plane *to_dcss_plane(struct drm_plane *p)
509021c317SLaurentiu Palcu {
519021c317SLaurentiu Palcu 	return container_of(p, struct dcss_plane, base);
529021c317SLaurentiu Palcu }
539021c317SLaurentiu Palcu 
dcss_plane_fb_is_linear(const struct drm_framebuffer * fb)549021c317SLaurentiu Palcu static inline bool dcss_plane_fb_is_linear(const struct drm_framebuffer *fb)
559021c317SLaurentiu Palcu {
569021c317SLaurentiu Palcu 	return ((fb->flags & DRM_MODE_FB_MODIFIERS) == 0) ||
579021c317SLaurentiu Palcu 	       ((fb->flags & DRM_MODE_FB_MODIFIERS) != 0 &&
589021c317SLaurentiu Palcu 		fb->modifier == DRM_FORMAT_MOD_LINEAR);
599021c317SLaurentiu Palcu }
609021c317SLaurentiu Palcu 
dcss_plane_destroy(struct drm_plane * plane)619021c317SLaurentiu Palcu static void dcss_plane_destroy(struct drm_plane *plane)
629021c317SLaurentiu Palcu {
639021c317SLaurentiu Palcu 	struct dcss_plane *dcss_plane = container_of(plane, struct dcss_plane,
649021c317SLaurentiu Palcu 						     base);
659021c317SLaurentiu Palcu 
669021c317SLaurentiu Palcu 	drm_plane_cleanup(plane);
679021c317SLaurentiu Palcu 	kfree(dcss_plane);
689021c317SLaurentiu Palcu }
699021c317SLaurentiu Palcu 
dcss_plane_format_mod_supported(struct drm_plane * plane,u32 format,u64 modifier)709021c317SLaurentiu Palcu static bool dcss_plane_format_mod_supported(struct drm_plane *plane,
719021c317SLaurentiu Palcu 					    u32 format,
729021c317SLaurentiu Palcu 					    u64 modifier)
739021c317SLaurentiu Palcu {
749021c317SLaurentiu Palcu 	switch (plane->type) {
759021c317SLaurentiu Palcu 	case DRM_PLANE_TYPE_PRIMARY:
769021c317SLaurentiu Palcu 		switch (format) {
779021c317SLaurentiu Palcu 		case DRM_FORMAT_ARGB8888:
789021c317SLaurentiu Palcu 		case DRM_FORMAT_XRGB8888:
799021c317SLaurentiu Palcu 		case DRM_FORMAT_ARGB2101010:
809021c317SLaurentiu Palcu 			return modifier == DRM_FORMAT_MOD_LINEAR ||
819021c317SLaurentiu Palcu 			       modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
829021c317SLaurentiu Palcu 			       modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED;
839021c317SLaurentiu Palcu 		default:
849021c317SLaurentiu Palcu 			return modifier == DRM_FORMAT_MOD_LINEAR;
859021c317SLaurentiu Palcu 		}
869021c317SLaurentiu Palcu 		break;
879021c317SLaurentiu Palcu 	case DRM_PLANE_TYPE_OVERLAY:
889021c317SLaurentiu Palcu 		return modifier == DRM_FORMAT_MOD_LINEAR;
899021c317SLaurentiu Palcu 	default:
909021c317SLaurentiu Palcu 		return false;
919021c317SLaurentiu Palcu 	}
929021c317SLaurentiu Palcu }
939021c317SLaurentiu Palcu 
949021c317SLaurentiu Palcu static const struct drm_plane_funcs dcss_plane_funcs = {
959021c317SLaurentiu Palcu 	.update_plane		= drm_atomic_helper_update_plane,
969021c317SLaurentiu Palcu 	.disable_plane		= drm_atomic_helper_disable_plane,
979021c317SLaurentiu Palcu 	.destroy		= dcss_plane_destroy,
989021c317SLaurentiu Palcu 	.reset			= drm_atomic_helper_plane_reset,
999021c317SLaurentiu Palcu 	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
1009021c317SLaurentiu Palcu 	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
1019021c317SLaurentiu Palcu 	.format_mod_supported	= dcss_plane_format_mod_supported,
1029021c317SLaurentiu Palcu };
1039021c317SLaurentiu Palcu 
dcss_plane_can_rotate(const struct drm_format_info * format,bool mod_present,u64 modifier,unsigned int rotation)1049021c317SLaurentiu Palcu static bool dcss_plane_can_rotate(const struct drm_format_info *format,
1059021c317SLaurentiu Palcu 				  bool mod_present, u64 modifier,
1069021c317SLaurentiu Palcu 				  unsigned int rotation)
1079021c317SLaurentiu Palcu {
108594486b5SLaurentiu Palcu 	bool linear_format = !mod_present || modifier == DRM_FORMAT_MOD_LINEAR;
1099021c317SLaurentiu Palcu 	u32 supported_rotation = DRM_MODE_ROTATE_0;
1109021c317SLaurentiu Palcu 
1119021c317SLaurentiu Palcu 	if (!format->is_yuv && linear_format)
1129021c317SLaurentiu Palcu 		supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
1139021c317SLaurentiu Palcu 				     DRM_MODE_REFLECT_MASK;
1149021c317SLaurentiu Palcu 	else if (!format->is_yuv &&
11559cb403fSLaurentiu Palcu 		 (modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
11659cb403fSLaurentiu Palcu 		  modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED))
1179021c317SLaurentiu Palcu 		supported_rotation = DRM_MODE_ROTATE_MASK |
1189021c317SLaurentiu Palcu 				     DRM_MODE_REFLECT_MASK;
1199021c317SLaurentiu Palcu 	else if (format->is_yuv && linear_format &&
1209021c317SLaurentiu Palcu 		 (format->format == DRM_FORMAT_NV12 ||
1219021c317SLaurentiu Palcu 		  format->format == DRM_FORMAT_NV21))
1229021c317SLaurentiu Palcu 		supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
1239021c317SLaurentiu Palcu 				     DRM_MODE_REFLECT_MASK;
1249021c317SLaurentiu Palcu 
1259021c317SLaurentiu Palcu 	return !!(rotation & supported_rotation);
1269021c317SLaurentiu Palcu }
1279021c317SLaurentiu Palcu 
dcss_plane_is_source_size_allowed(u16 src_w,u16 src_h,u32 pix_fmt)1289021c317SLaurentiu Palcu static bool dcss_plane_is_source_size_allowed(u16 src_w, u16 src_h, u32 pix_fmt)
1299021c317SLaurentiu Palcu {
1309021c317SLaurentiu Palcu 	if (src_w < 64 &&
1319021c317SLaurentiu Palcu 	    (pix_fmt == DRM_FORMAT_NV12 || pix_fmt == DRM_FORMAT_NV21))
1329021c317SLaurentiu Palcu 		return false;
1339021c317SLaurentiu Palcu 	else if (src_w < 32 &&
1349021c317SLaurentiu Palcu 		 (pix_fmt == DRM_FORMAT_UYVY || pix_fmt == DRM_FORMAT_VYUY ||
1359021c317SLaurentiu Palcu 		  pix_fmt == DRM_FORMAT_YUYV || pix_fmt == DRM_FORMAT_YVYU))
1369021c317SLaurentiu Palcu 		return false;
1379021c317SLaurentiu Palcu 
1389021c317SLaurentiu Palcu 	return src_w >= 16 && src_h >= 8;
1399021c317SLaurentiu Palcu }
1409021c317SLaurentiu Palcu 
dcss_plane_atomic_check(struct drm_plane * plane,struct drm_atomic_state * state)1419021c317SLaurentiu Palcu static int dcss_plane_atomic_check(struct drm_plane *plane,
1427c11b99aSMaxime Ripard 				   struct drm_atomic_state *state)
1439021c317SLaurentiu Palcu {
1447c11b99aSMaxime Ripard 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
1457c11b99aSMaxime Ripard 										 plane);
1469021c317SLaurentiu Palcu 	struct dcss_plane *dcss_plane = to_dcss_plane(plane);
1479021c317SLaurentiu Palcu 	struct dcss_dev *dcss = plane->dev->dev_private;
148ba5c1649SMaxime Ripard 	struct drm_framebuffer *fb = new_plane_state->fb;
1499021c317SLaurentiu Palcu 	bool is_primary_plane = plane->type == DRM_PLANE_TYPE_PRIMARY;
1504a83c26aSDanilo Krummrich 	struct drm_gem_dma_object *dma_obj;
1519021c317SLaurentiu Palcu 	struct drm_crtc_state *crtc_state;
1529021c317SLaurentiu Palcu 	int hdisplay, vdisplay;
1539021c317SLaurentiu Palcu 	int min, max;
1549021c317SLaurentiu Palcu 	int ret;
1559021c317SLaurentiu Palcu 
156ba5c1649SMaxime Ripard 	if (!fb || !new_plane_state->crtc)
1579021c317SLaurentiu Palcu 		return 0;
1589021c317SLaurentiu Palcu 
1594a83c26aSDanilo Krummrich 	dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
1604a83c26aSDanilo Krummrich 	WARN_ON(!dma_obj);
1619021c317SLaurentiu Palcu 
162dec92020SMaxime Ripard 	crtc_state = drm_atomic_get_existing_crtc_state(state,
163ba5c1649SMaxime Ripard 							new_plane_state->crtc);
1649021c317SLaurentiu Palcu 
1659021c317SLaurentiu Palcu 	hdisplay = crtc_state->adjusted_mode.hdisplay;
1669021c317SLaurentiu Palcu 	vdisplay = crtc_state->adjusted_mode.vdisplay;
1679021c317SLaurentiu Palcu 
168ba5c1649SMaxime Ripard 	if (!dcss_plane_is_source_size_allowed(new_plane_state->src_w >> 16,
169ba5c1649SMaxime Ripard 					       new_plane_state->src_h >> 16,
1709021c317SLaurentiu Palcu 					       fb->format->format)) {
1719021c317SLaurentiu Palcu 		DRM_DEBUG_KMS("Source plane size is not allowed!\n");
1729021c317SLaurentiu Palcu 		return -EINVAL;
1739021c317SLaurentiu Palcu 	}
1749021c317SLaurentiu Palcu 
1759021c317SLaurentiu Palcu 	dcss_scaler_get_min_max_ratios(dcss->scaler, dcss_plane->ch_num,
1769021c317SLaurentiu Palcu 				       &min, &max);
1779021c317SLaurentiu Palcu 
178ba5c1649SMaxime Ripard 	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
1799021c317SLaurentiu Palcu 						  min, max, !is_primary_plane,
1809021c317SLaurentiu Palcu 						  false);
1819021c317SLaurentiu Palcu 	if (ret)
1829021c317SLaurentiu Palcu 		return ret;
1839021c317SLaurentiu Palcu 
184ba5c1649SMaxime Ripard 	if (!new_plane_state->visible)
1859021c317SLaurentiu Palcu 		return 0;
1869021c317SLaurentiu Palcu 
1879021c317SLaurentiu Palcu 	if (!dcss_plane_can_rotate(fb->format,
1889021c317SLaurentiu Palcu 				   !!(fb->flags & DRM_MODE_FB_MODIFIERS),
1899021c317SLaurentiu Palcu 				   fb->modifier,
190ba5c1649SMaxime Ripard 				   new_plane_state->rotation)) {
1919021c317SLaurentiu Palcu 		DRM_DEBUG_KMS("requested rotation is not allowed!\n");
1929021c317SLaurentiu Palcu 		return -EINVAL;
1939021c317SLaurentiu Palcu 	}
1949021c317SLaurentiu Palcu 
195ba5c1649SMaxime Ripard 	if ((new_plane_state->crtc_x < 0 || new_plane_state->crtc_y < 0 ||
196ba5c1649SMaxime Ripard 	     new_plane_state->crtc_x + new_plane_state->crtc_w > hdisplay ||
197ba5c1649SMaxime Ripard 	     new_plane_state->crtc_y + new_plane_state->crtc_h > vdisplay) &&
1989021c317SLaurentiu Palcu 	    !dcss_plane_fb_is_linear(fb)) {
1999021c317SLaurentiu Palcu 		DRM_DEBUG_KMS("requested cropping operation is not allowed!\n");
2009021c317SLaurentiu Palcu 		return -EINVAL;
2019021c317SLaurentiu Palcu 	}
2029021c317SLaurentiu Palcu 
2039021c317SLaurentiu Palcu 	if ((fb->flags & DRM_MODE_FB_MODIFIERS) &&
2049021c317SLaurentiu Palcu 	    !plane->funcs->format_mod_supported(plane,
2059021c317SLaurentiu Palcu 				fb->format->format,
2069021c317SLaurentiu Palcu 				fb->modifier)) {
2079021c317SLaurentiu Palcu 		DRM_DEBUG_KMS("Invalid modifier: %llx", fb->modifier);
2089021c317SLaurentiu Palcu 		return -EINVAL;
2099021c317SLaurentiu Palcu 	}
2109021c317SLaurentiu Palcu 
2119021c317SLaurentiu Palcu 	return 0;
2129021c317SLaurentiu Palcu }
2139021c317SLaurentiu Palcu 
dcss_plane_atomic_set_base(struct dcss_plane * dcss_plane)2149021c317SLaurentiu Palcu static void dcss_plane_atomic_set_base(struct dcss_plane *dcss_plane)
2159021c317SLaurentiu Palcu {
2169021c317SLaurentiu Palcu 	struct drm_plane *plane = &dcss_plane->base;
2179021c317SLaurentiu Palcu 	struct drm_plane_state *state = plane->state;
2189021c317SLaurentiu Palcu 	struct dcss_dev *dcss = plane->dev->dev_private;
2199021c317SLaurentiu Palcu 	struct drm_framebuffer *fb = state->fb;
2209021c317SLaurentiu Palcu 	const struct drm_format_info *format = fb->format;
2214a83c26aSDanilo Krummrich 	struct drm_gem_dma_object *dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
2229021c317SLaurentiu Palcu 	unsigned long p1_ba = 0, p2_ba = 0;
2239021c317SLaurentiu Palcu 
2249021c317SLaurentiu Palcu 	if (!format->is_yuv ||
2259021c317SLaurentiu Palcu 	    format->format == DRM_FORMAT_NV12 ||
2269021c317SLaurentiu Palcu 	    format->format == DRM_FORMAT_NV21)
227*8c30eeccSDanilo Krummrich 		p1_ba = dma_obj->dma_addr + fb->offsets[0] +
2289021c317SLaurentiu Palcu 			fb->pitches[0] * (state->src.y1 >> 16) +
2299021c317SLaurentiu Palcu 			format->char_per_block[0] * (state->src.x1 >> 16);
2309021c317SLaurentiu Palcu 	else if (format->format == DRM_FORMAT_UYVY ||
2319021c317SLaurentiu Palcu 		 format->format == DRM_FORMAT_VYUY ||
2329021c317SLaurentiu Palcu 		 format->format == DRM_FORMAT_YUYV ||
2339021c317SLaurentiu Palcu 		 format->format == DRM_FORMAT_YVYU)
234*8c30eeccSDanilo Krummrich 		p1_ba = dma_obj->dma_addr + fb->offsets[0] +
2359021c317SLaurentiu Palcu 			fb->pitches[0] * (state->src.y1 >> 16) +
2369021c317SLaurentiu Palcu 			2 * format->char_per_block[0] * (state->src.x1 >> 17);
2379021c317SLaurentiu Palcu 
2389021c317SLaurentiu Palcu 	if (format->format == DRM_FORMAT_NV12 ||
2399021c317SLaurentiu Palcu 	    format->format == DRM_FORMAT_NV21)
240*8c30eeccSDanilo Krummrich 		p2_ba = dma_obj->dma_addr + fb->offsets[1] +
2419021c317SLaurentiu Palcu 			(((fb->pitches[1] >> 1) * (state->src.y1 >> 17) +
2429021c317SLaurentiu Palcu 			(state->src.x1 >> 17)) << 1);
2439021c317SLaurentiu Palcu 
2449021c317SLaurentiu Palcu 	dcss_dpr_addr_set(dcss->dpr, dcss_plane->ch_num, p1_ba, p2_ba,
2459021c317SLaurentiu Palcu 			  fb->pitches[0]);
2469021c317SLaurentiu Palcu }
2479021c317SLaurentiu Palcu 
dcss_plane_needs_setup(struct drm_plane_state * state,struct drm_plane_state * old_state)2489021c317SLaurentiu Palcu static bool dcss_plane_needs_setup(struct drm_plane_state *state,
2499021c317SLaurentiu Palcu 				   struct drm_plane_state *old_state)
2509021c317SLaurentiu Palcu {
2519021c317SLaurentiu Palcu 	struct drm_framebuffer *fb = state->fb;
2529021c317SLaurentiu Palcu 	struct drm_framebuffer *old_fb = old_state->fb;
2539021c317SLaurentiu Palcu 
2549021c317SLaurentiu Palcu 	return state->crtc_x != old_state->crtc_x ||
2559021c317SLaurentiu Palcu 	       state->crtc_y != old_state->crtc_y ||
2569021c317SLaurentiu Palcu 	       state->crtc_w != old_state->crtc_w ||
2579021c317SLaurentiu Palcu 	       state->crtc_h != old_state->crtc_h ||
2589021c317SLaurentiu Palcu 	       state->src_x  != old_state->src_x  ||
2599021c317SLaurentiu Palcu 	       state->src_y  != old_state->src_y  ||
2609021c317SLaurentiu Palcu 	       state->src_w  != old_state->src_w  ||
2619021c317SLaurentiu Palcu 	       state->src_h  != old_state->src_h  ||
2629021c317SLaurentiu Palcu 	       fb->format->format != old_fb->format->format ||
2639021c317SLaurentiu Palcu 	       fb->modifier  != old_fb->modifier ||
26405faf155SLaurentiu Palcu 	       state->rotation != old_state->rotation ||
26505faf155SLaurentiu Palcu 	       state->scaling_filter != old_state->scaling_filter;
2669021c317SLaurentiu Palcu }
2679021c317SLaurentiu Palcu 
dcss_plane_atomic_update(struct drm_plane * plane,struct drm_atomic_state * state)2689021c317SLaurentiu Palcu static void dcss_plane_atomic_update(struct drm_plane *plane,
269977697e2SMaxime Ripard 				     struct drm_atomic_state *state)
2709021c317SLaurentiu Palcu {
271977697e2SMaxime Ripard 	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
272977697e2SMaxime Ripard 									   plane);
27337418bf1SMaxime Ripard 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
27437418bf1SMaxime Ripard 									   plane);
2759021c317SLaurentiu Palcu 	struct dcss_plane *dcss_plane = to_dcss_plane(plane);
2769021c317SLaurentiu Palcu 	struct dcss_dev *dcss = plane->dev->dev_private;
27741016fe1SMaxime Ripard 	struct drm_framebuffer *fb = new_state->fb;
2789021c317SLaurentiu Palcu 	struct drm_crtc_state *crtc_state;
2799021c317SLaurentiu Palcu 	bool modifiers_present;
2809021c317SLaurentiu Palcu 	u32 src_w, src_h, dst_w, dst_h;
2819021c317SLaurentiu Palcu 	struct drm_rect src, dst;
2829021c317SLaurentiu Palcu 	bool enable = true;
28359cb403fSLaurentiu Palcu 	bool is_rotation_90_or_270;
2849021c317SLaurentiu Palcu 
28541016fe1SMaxime Ripard 	if (!fb || !new_state->crtc || !new_state->visible)
2869021c317SLaurentiu Palcu 		return;
2879021c317SLaurentiu Palcu 
28841016fe1SMaxime Ripard 	crtc_state = new_state->crtc->state;
2899021c317SLaurentiu Palcu 	modifiers_present = !!(fb->flags & DRM_MODE_FB_MODIFIERS);
2909021c317SLaurentiu Palcu 
2919021c317SLaurentiu Palcu 	if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state) &&
29241016fe1SMaxime Ripard 	    !dcss_plane_needs_setup(new_state, old_state)) {
2939021c317SLaurentiu Palcu 		dcss_plane_atomic_set_base(dcss_plane);
2949021c317SLaurentiu Palcu 		return;
2959021c317SLaurentiu Palcu 	}
2969021c317SLaurentiu Palcu 
2979021c317SLaurentiu Palcu 	src = plane->state->src;
2989021c317SLaurentiu Palcu 	dst = plane->state->dst;
2999021c317SLaurentiu Palcu 
3009021c317SLaurentiu Palcu 	/*
3019021c317SLaurentiu Palcu 	 * The width and height after clipping.
3029021c317SLaurentiu Palcu 	 */
3039021c317SLaurentiu Palcu 	src_w = drm_rect_width(&src) >> 16;
3049021c317SLaurentiu Palcu 	src_h = drm_rect_height(&src) >> 16;
3059021c317SLaurentiu Palcu 	dst_w = drm_rect_width(&dst);
3069021c317SLaurentiu Palcu 	dst_h = drm_rect_height(&dst);
3079021c317SLaurentiu Palcu 
3089021c317SLaurentiu Palcu 	if (plane->type == DRM_PLANE_TYPE_OVERLAY &&
3099021c317SLaurentiu Palcu 	    modifiers_present && fb->modifier == DRM_FORMAT_MOD_LINEAR)
3109021c317SLaurentiu Palcu 		modifiers_present = false;
3119021c317SLaurentiu Palcu 
31241016fe1SMaxime Ripard 	dcss_dpr_format_set(dcss->dpr, dcss_plane->ch_num,
31341016fe1SMaxime Ripard 			    new_state->fb->format,
3149021c317SLaurentiu Palcu 			    modifiers_present ? fb->modifier :
3159021c317SLaurentiu Palcu 						DRM_FORMAT_MOD_LINEAR);
3169021c317SLaurentiu Palcu 	dcss_dpr_set_res(dcss->dpr, dcss_plane->ch_num, src_w, src_h);
3179021c317SLaurentiu Palcu 	dcss_dpr_set_rotation(dcss->dpr, dcss_plane->ch_num,
31841016fe1SMaxime Ripard 			      new_state->rotation);
3199021c317SLaurentiu Palcu 
3209021c317SLaurentiu Palcu 	dcss_plane_atomic_set_base(dcss_plane);
3219021c317SLaurentiu Palcu 
32241016fe1SMaxime Ripard 	is_rotation_90_or_270 = new_state->rotation & (DRM_MODE_ROTATE_90 |
32359cb403fSLaurentiu Palcu 						   DRM_MODE_ROTATE_270);
32459cb403fSLaurentiu Palcu 
32505faf155SLaurentiu Palcu 	dcss_scaler_set_filter(dcss->scaler, dcss_plane->ch_num,
32641016fe1SMaxime Ripard 			       new_state->scaling_filter);
32705faf155SLaurentiu Palcu 
3289021c317SLaurentiu Palcu 	dcss_scaler_setup(dcss->scaler, dcss_plane->ch_num,
32941016fe1SMaxime Ripard 			  new_state->fb->format,
33059cb403fSLaurentiu Palcu 			  is_rotation_90_or_270 ? src_h : src_w,
33159cb403fSLaurentiu Palcu 			  is_rotation_90_or_270 ? src_w : src_h,
3329021c317SLaurentiu Palcu 			  dst_w, dst_h,
3339021c317SLaurentiu Palcu 			  drm_mode_vrefresh(&crtc_state->mode));
3349021c317SLaurentiu Palcu 
3359021c317SLaurentiu Palcu 	dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
3369021c317SLaurentiu Palcu 			       dst.x1, dst.y1, dst_w, dst_h);
3379021c317SLaurentiu Palcu 	dcss_dtg_plane_alpha_set(dcss->dtg, dcss_plane->ch_num,
33841016fe1SMaxime Ripard 				 fb->format, new_state->alpha >> 8);
3399021c317SLaurentiu Palcu 
34041016fe1SMaxime Ripard 	if (!dcss_plane->ch_num && (new_state->alpha >> 8) == 0)
3419021c317SLaurentiu Palcu 		enable = false;
3429021c317SLaurentiu Palcu 
3439021c317SLaurentiu Palcu 	dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, enable);
3449021c317SLaurentiu Palcu 	dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, enable);
3459021c317SLaurentiu Palcu 
3469021c317SLaurentiu Palcu 	if (!enable)
3479021c317SLaurentiu Palcu 		dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
3489021c317SLaurentiu Palcu 				       0, 0, 0, 0);
3499021c317SLaurentiu Palcu 
3509021c317SLaurentiu Palcu 	dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, enable);
3519021c317SLaurentiu Palcu }
3529021c317SLaurentiu Palcu 
dcss_plane_atomic_disable(struct drm_plane * plane,struct drm_atomic_state * state)3539021c317SLaurentiu Palcu static void dcss_plane_atomic_disable(struct drm_plane *plane,
354977697e2SMaxime Ripard 				      struct drm_atomic_state *state)
3559021c317SLaurentiu Palcu {
3569021c317SLaurentiu Palcu 	struct dcss_plane *dcss_plane = to_dcss_plane(plane);
3579021c317SLaurentiu Palcu 	struct dcss_dev *dcss = plane->dev->dev_private;
3589021c317SLaurentiu Palcu 
3599021c317SLaurentiu Palcu 	dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, false);
3609021c317SLaurentiu Palcu 	dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, false);
3619021c317SLaurentiu Palcu 	dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num, 0, 0, 0, 0);
3629021c317SLaurentiu Palcu 	dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, false);
3639021c317SLaurentiu Palcu }
3649021c317SLaurentiu Palcu 
3659021c317SLaurentiu Palcu static const struct drm_plane_helper_funcs dcss_plane_helper_funcs = {
3669021c317SLaurentiu Palcu 	.atomic_check = dcss_plane_atomic_check,
3679021c317SLaurentiu Palcu 	.atomic_update = dcss_plane_atomic_update,
3689021c317SLaurentiu Palcu 	.atomic_disable = dcss_plane_atomic_disable,
3699021c317SLaurentiu Palcu };
3709021c317SLaurentiu Palcu 
dcss_plane_init(struct drm_device * drm,unsigned int possible_crtcs,enum drm_plane_type type,unsigned int zpos)3719021c317SLaurentiu Palcu struct dcss_plane *dcss_plane_init(struct drm_device *drm,
3729021c317SLaurentiu Palcu 				   unsigned int possible_crtcs,
3739021c317SLaurentiu Palcu 				   enum drm_plane_type type,
3749021c317SLaurentiu Palcu 				   unsigned int zpos)
3759021c317SLaurentiu Palcu {
3769021c317SLaurentiu Palcu 	struct dcss_plane *dcss_plane;
3779021c317SLaurentiu Palcu 	const u64 *format_modifiers = dcss_video_format_modifiers;
3789021c317SLaurentiu Palcu 	int ret;
3799021c317SLaurentiu Palcu 
3809021c317SLaurentiu Palcu 	if (zpos > 2)
3819021c317SLaurentiu Palcu 		return ERR_PTR(-EINVAL);
3829021c317SLaurentiu Palcu 
3839021c317SLaurentiu Palcu 	dcss_plane = kzalloc(sizeof(*dcss_plane), GFP_KERNEL);
3849021c317SLaurentiu Palcu 	if (!dcss_plane) {
3859021c317SLaurentiu Palcu 		DRM_ERROR("failed to allocate plane\n");
3869021c317SLaurentiu Palcu 		return ERR_PTR(-ENOMEM);
3879021c317SLaurentiu Palcu 	}
3889021c317SLaurentiu Palcu 
3899021c317SLaurentiu Palcu 	if (type == DRM_PLANE_TYPE_PRIMARY)
3909021c317SLaurentiu Palcu 		format_modifiers = dcss_graphics_format_modifiers;
3919021c317SLaurentiu Palcu 
3929021c317SLaurentiu Palcu 	ret = drm_universal_plane_init(drm, &dcss_plane->base, possible_crtcs,
3939021c317SLaurentiu Palcu 				       &dcss_plane_funcs, dcss_common_formats,
3949021c317SLaurentiu Palcu 				       ARRAY_SIZE(dcss_common_formats),
3959021c317SLaurentiu Palcu 				       format_modifiers, type, NULL);
3969021c317SLaurentiu Palcu 	if (ret) {
3979021c317SLaurentiu Palcu 		DRM_ERROR("failed to initialize plane\n");
3989021c317SLaurentiu Palcu 		kfree(dcss_plane);
3999021c317SLaurentiu Palcu 		return ERR_PTR(ret);
4009021c317SLaurentiu Palcu 	}
4019021c317SLaurentiu Palcu 
4029021c317SLaurentiu Palcu 	drm_plane_helper_add(&dcss_plane->base, &dcss_plane_helper_funcs);
4039021c317SLaurentiu Palcu 
4049021c317SLaurentiu Palcu 	ret = drm_plane_create_zpos_immutable_property(&dcss_plane->base, zpos);
4059021c317SLaurentiu Palcu 	if (ret)
4069021c317SLaurentiu Palcu 		return ERR_PTR(ret);
4079021c317SLaurentiu Palcu 
40805faf155SLaurentiu Palcu 	drm_plane_create_scaling_filter_property(&dcss_plane->base,
40905faf155SLaurentiu Palcu 					BIT(DRM_SCALING_FILTER_DEFAULT) |
41005faf155SLaurentiu Palcu 					BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
41105faf155SLaurentiu Palcu 
4129021c317SLaurentiu Palcu 	drm_plane_create_rotation_property(&dcss_plane->base,
4139021c317SLaurentiu Palcu 					   DRM_MODE_ROTATE_0,
4149021c317SLaurentiu Palcu 					   DRM_MODE_ROTATE_0   |
4159021c317SLaurentiu Palcu 					   DRM_MODE_ROTATE_90  |
4169021c317SLaurentiu Palcu 					   DRM_MODE_ROTATE_180 |
4179021c317SLaurentiu Palcu 					   DRM_MODE_ROTATE_270 |
4189021c317SLaurentiu Palcu 					   DRM_MODE_REFLECT_X  |
4199021c317SLaurentiu Palcu 					   DRM_MODE_REFLECT_Y);
4209021c317SLaurentiu Palcu 
4219021c317SLaurentiu Palcu 	dcss_plane->ch_num = zpos;
4229021c317SLaurentiu Palcu 
4239021c317SLaurentiu Palcu 	return dcss_plane;
4249021c317SLaurentiu Palcu }
425