18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2019 NXP.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <drm/drm_atomic.h>
78c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h>
88c2ecf20Sopenharmony_ci#include <drm/drm_fb_cma_helper.h>
98c2ecf20Sopenharmony_ci#include <drm/drm_gem_framebuffer_helper.h>
108c2ecf20Sopenharmony_ci#include <drm/drm_gem_cma_helper.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "dcss-dev.h"
138c2ecf20Sopenharmony_ci#include "dcss-kms.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistatic const u32 dcss_common_formats[] = {
168c2ecf20Sopenharmony_ci	/* RGB */
178c2ecf20Sopenharmony_ci	DRM_FORMAT_ARGB8888,
188c2ecf20Sopenharmony_ci	DRM_FORMAT_XRGB8888,
198c2ecf20Sopenharmony_ci	DRM_FORMAT_ABGR8888,
208c2ecf20Sopenharmony_ci	DRM_FORMAT_XBGR8888,
218c2ecf20Sopenharmony_ci	DRM_FORMAT_RGBA8888,
228c2ecf20Sopenharmony_ci	DRM_FORMAT_RGBX8888,
238c2ecf20Sopenharmony_ci	DRM_FORMAT_BGRA8888,
248c2ecf20Sopenharmony_ci	DRM_FORMAT_BGRX8888,
258c2ecf20Sopenharmony_ci	DRM_FORMAT_XRGB2101010,
268c2ecf20Sopenharmony_ci	DRM_FORMAT_XBGR2101010,
278c2ecf20Sopenharmony_ci	DRM_FORMAT_RGBX1010102,
288c2ecf20Sopenharmony_ci	DRM_FORMAT_BGRX1010102,
298c2ecf20Sopenharmony_ci	DRM_FORMAT_ARGB2101010,
308c2ecf20Sopenharmony_ci	DRM_FORMAT_ABGR2101010,
318c2ecf20Sopenharmony_ci	DRM_FORMAT_RGBA1010102,
328c2ecf20Sopenharmony_ci	DRM_FORMAT_BGRA1010102,
338c2ecf20Sopenharmony_ci};
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic const u64 dcss_video_format_modifiers[] = {
368c2ecf20Sopenharmony_ci	DRM_FORMAT_MOD_LINEAR,
378c2ecf20Sopenharmony_ci	DRM_FORMAT_MOD_INVALID,
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic const u64 dcss_graphics_format_modifiers[] = {
418c2ecf20Sopenharmony_ci	DRM_FORMAT_MOD_VIVANTE_TILED,
428c2ecf20Sopenharmony_ci	DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
438c2ecf20Sopenharmony_ci	DRM_FORMAT_MOD_LINEAR,
448c2ecf20Sopenharmony_ci	DRM_FORMAT_MOD_INVALID,
458c2ecf20Sopenharmony_ci};
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic inline struct dcss_plane *to_dcss_plane(struct drm_plane *p)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	return container_of(p, struct dcss_plane, base);
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic inline bool dcss_plane_fb_is_linear(const struct drm_framebuffer *fb)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	return ((fb->flags & DRM_MODE_FB_MODIFIERS) == 0) ||
558c2ecf20Sopenharmony_ci	       ((fb->flags & DRM_MODE_FB_MODIFIERS) != 0 &&
568c2ecf20Sopenharmony_ci		fb->modifier == DRM_FORMAT_MOD_LINEAR);
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic void dcss_plane_destroy(struct drm_plane *plane)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	struct dcss_plane *dcss_plane = container_of(plane, struct dcss_plane,
628c2ecf20Sopenharmony_ci						     base);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	drm_plane_cleanup(plane);
658c2ecf20Sopenharmony_ci	kfree(dcss_plane);
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic bool dcss_plane_format_mod_supported(struct drm_plane *plane,
698c2ecf20Sopenharmony_ci					    u32 format,
708c2ecf20Sopenharmony_ci					    u64 modifier)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	switch (plane->type) {
738c2ecf20Sopenharmony_ci	case DRM_PLANE_TYPE_PRIMARY:
748c2ecf20Sopenharmony_ci		switch (format) {
758c2ecf20Sopenharmony_ci		case DRM_FORMAT_ARGB8888:
768c2ecf20Sopenharmony_ci		case DRM_FORMAT_XRGB8888:
778c2ecf20Sopenharmony_ci		case DRM_FORMAT_ARGB2101010:
788c2ecf20Sopenharmony_ci			return modifier == DRM_FORMAT_MOD_LINEAR ||
798c2ecf20Sopenharmony_ci			       modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
808c2ecf20Sopenharmony_ci			       modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED;
818c2ecf20Sopenharmony_ci		default:
828c2ecf20Sopenharmony_ci			return modifier == DRM_FORMAT_MOD_LINEAR;
838c2ecf20Sopenharmony_ci		}
848c2ecf20Sopenharmony_ci		break;
858c2ecf20Sopenharmony_ci	case DRM_PLANE_TYPE_OVERLAY:
868c2ecf20Sopenharmony_ci		return modifier == DRM_FORMAT_MOD_LINEAR;
878c2ecf20Sopenharmony_ci	default:
888c2ecf20Sopenharmony_ci		return false;
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic const struct drm_plane_funcs dcss_plane_funcs = {
938c2ecf20Sopenharmony_ci	.update_plane		= drm_atomic_helper_update_plane,
948c2ecf20Sopenharmony_ci	.disable_plane		= drm_atomic_helper_disable_plane,
958c2ecf20Sopenharmony_ci	.destroy		= dcss_plane_destroy,
968c2ecf20Sopenharmony_ci	.reset			= drm_atomic_helper_plane_reset,
978c2ecf20Sopenharmony_ci	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
988c2ecf20Sopenharmony_ci	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
998c2ecf20Sopenharmony_ci	.format_mod_supported	= dcss_plane_format_mod_supported,
1008c2ecf20Sopenharmony_ci};
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic bool dcss_plane_can_rotate(const struct drm_format_info *format,
1038c2ecf20Sopenharmony_ci				  bool mod_present, u64 modifier,
1048c2ecf20Sopenharmony_ci				  unsigned int rotation)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	bool linear_format = !mod_present ||
1078c2ecf20Sopenharmony_ci			     (mod_present && modifier == DRM_FORMAT_MOD_LINEAR);
1088c2ecf20Sopenharmony_ci	u32 supported_rotation = DRM_MODE_ROTATE_0;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	if (!format->is_yuv && linear_format)
1118c2ecf20Sopenharmony_ci		supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
1128c2ecf20Sopenharmony_ci				     DRM_MODE_REFLECT_MASK;
1138c2ecf20Sopenharmony_ci	else if (!format->is_yuv &&
1148c2ecf20Sopenharmony_ci		 (modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
1158c2ecf20Sopenharmony_ci		  modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED))
1168c2ecf20Sopenharmony_ci		supported_rotation = DRM_MODE_ROTATE_MASK |
1178c2ecf20Sopenharmony_ci				     DRM_MODE_REFLECT_MASK;
1188c2ecf20Sopenharmony_ci	else if (format->is_yuv && linear_format &&
1198c2ecf20Sopenharmony_ci		 (format->format == DRM_FORMAT_NV12 ||
1208c2ecf20Sopenharmony_ci		  format->format == DRM_FORMAT_NV21))
1218c2ecf20Sopenharmony_ci		supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
1228c2ecf20Sopenharmony_ci				     DRM_MODE_REFLECT_MASK;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	return !!(rotation & supported_rotation);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic bool dcss_plane_is_source_size_allowed(u16 src_w, u16 src_h, u32 pix_fmt)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	if (src_w < 64 &&
1308c2ecf20Sopenharmony_ci	    (pix_fmt == DRM_FORMAT_NV12 || pix_fmt == DRM_FORMAT_NV21))
1318c2ecf20Sopenharmony_ci		return false;
1328c2ecf20Sopenharmony_ci	else if (src_w < 32 &&
1338c2ecf20Sopenharmony_ci		 (pix_fmt == DRM_FORMAT_UYVY || pix_fmt == DRM_FORMAT_VYUY ||
1348c2ecf20Sopenharmony_ci		  pix_fmt == DRM_FORMAT_YUYV || pix_fmt == DRM_FORMAT_YVYU))
1358c2ecf20Sopenharmony_ci		return false;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	return src_w >= 16 && src_h >= 8;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic int dcss_plane_atomic_check(struct drm_plane *plane,
1418c2ecf20Sopenharmony_ci				   struct drm_plane_state *state)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	struct dcss_plane *dcss_plane = to_dcss_plane(plane);
1448c2ecf20Sopenharmony_ci	struct dcss_dev *dcss = plane->dev->dev_private;
1458c2ecf20Sopenharmony_ci	struct drm_framebuffer *fb = state->fb;
1468c2ecf20Sopenharmony_ci	bool is_primary_plane = plane->type == DRM_PLANE_TYPE_PRIMARY;
1478c2ecf20Sopenharmony_ci	struct drm_gem_cma_object *cma_obj;
1488c2ecf20Sopenharmony_ci	struct drm_crtc_state *crtc_state;
1498c2ecf20Sopenharmony_ci	int hdisplay, vdisplay;
1508c2ecf20Sopenharmony_ci	int min, max;
1518c2ecf20Sopenharmony_ci	int ret;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (!fb || !state->crtc)
1548c2ecf20Sopenharmony_ci		return 0;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
1578c2ecf20Sopenharmony_ci	WARN_ON(!cma_obj);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	crtc_state = drm_atomic_get_existing_crtc_state(state->state,
1608c2ecf20Sopenharmony_ci							state->crtc);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	hdisplay = crtc_state->adjusted_mode.hdisplay;
1638c2ecf20Sopenharmony_ci	vdisplay = crtc_state->adjusted_mode.vdisplay;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	if (!dcss_plane_is_source_size_allowed(state->src_w >> 16,
1668c2ecf20Sopenharmony_ci					       state->src_h >> 16,
1678c2ecf20Sopenharmony_ci					       fb->format->format)) {
1688c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("Source plane size is not allowed!\n");
1698c2ecf20Sopenharmony_ci		return -EINVAL;
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	dcss_scaler_get_min_max_ratios(dcss->scaler, dcss_plane->ch_num,
1738c2ecf20Sopenharmony_ci				       &min, &max);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	ret = drm_atomic_helper_check_plane_state(state, crtc_state,
1768c2ecf20Sopenharmony_ci						  min, max, !is_primary_plane,
1778c2ecf20Sopenharmony_ci						  false);
1788c2ecf20Sopenharmony_ci	if (ret)
1798c2ecf20Sopenharmony_ci		return ret;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	if (!state->visible)
1828c2ecf20Sopenharmony_ci		return 0;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	if (!dcss_plane_can_rotate(fb->format,
1858c2ecf20Sopenharmony_ci				   !!(fb->flags & DRM_MODE_FB_MODIFIERS),
1868c2ecf20Sopenharmony_ci				   fb->modifier,
1878c2ecf20Sopenharmony_ci				   state->rotation)) {
1888c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("requested rotation is not allowed!\n");
1898c2ecf20Sopenharmony_ci		return -EINVAL;
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if ((state->crtc_x < 0 || state->crtc_y < 0 ||
1938c2ecf20Sopenharmony_ci	     state->crtc_x + state->crtc_w > hdisplay ||
1948c2ecf20Sopenharmony_ci	     state->crtc_y + state->crtc_h > vdisplay) &&
1958c2ecf20Sopenharmony_ci	    !dcss_plane_fb_is_linear(fb)) {
1968c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("requested cropping operation is not allowed!\n");
1978c2ecf20Sopenharmony_ci		return -EINVAL;
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if ((fb->flags & DRM_MODE_FB_MODIFIERS) &&
2018c2ecf20Sopenharmony_ci	    !plane->funcs->format_mod_supported(plane,
2028c2ecf20Sopenharmony_ci				fb->format->format,
2038c2ecf20Sopenharmony_ci				fb->modifier)) {
2048c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("Invalid modifier: %llx", fb->modifier);
2058c2ecf20Sopenharmony_ci		return -EINVAL;
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	return 0;
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic void dcss_plane_atomic_set_base(struct dcss_plane *dcss_plane)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	struct drm_plane *plane = &dcss_plane->base;
2148c2ecf20Sopenharmony_ci	struct drm_plane_state *state = plane->state;
2158c2ecf20Sopenharmony_ci	struct dcss_dev *dcss = plane->dev->dev_private;
2168c2ecf20Sopenharmony_ci	struct drm_framebuffer *fb = state->fb;
2178c2ecf20Sopenharmony_ci	const struct drm_format_info *format = fb->format;
2188c2ecf20Sopenharmony_ci	struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
2198c2ecf20Sopenharmony_ci	unsigned long p1_ba = 0, p2_ba = 0;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (!format->is_yuv ||
2228c2ecf20Sopenharmony_ci	    format->format == DRM_FORMAT_NV12 ||
2238c2ecf20Sopenharmony_ci	    format->format == DRM_FORMAT_NV21)
2248c2ecf20Sopenharmony_ci		p1_ba = cma_obj->paddr + fb->offsets[0] +
2258c2ecf20Sopenharmony_ci			fb->pitches[0] * (state->src.y1 >> 16) +
2268c2ecf20Sopenharmony_ci			format->char_per_block[0] * (state->src.x1 >> 16);
2278c2ecf20Sopenharmony_ci	else if (format->format == DRM_FORMAT_UYVY ||
2288c2ecf20Sopenharmony_ci		 format->format == DRM_FORMAT_VYUY ||
2298c2ecf20Sopenharmony_ci		 format->format == DRM_FORMAT_YUYV ||
2308c2ecf20Sopenharmony_ci		 format->format == DRM_FORMAT_YVYU)
2318c2ecf20Sopenharmony_ci		p1_ba = cma_obj->paddr + fb->offsets[0] +
2328c2ecf20Sopenharmony_ci			fb->pitches[0] * (state->src.y1 >> 16) +
2338c2ecf20Sopenharmony_ci			2 * format->char_per_block[0] * (state->src.x1 >> 17);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (format->format == DRM_FORMAT_NV12 ||
2368c2ecf20Sopenharmony_ci	    format->format == DRM_FORMAT_NV21)
2378c2ecf20Sopenharmony_ci		p2_ba = cma_obj->paddr + fb->offsets[1] +
2388c2ecf20Sopenharmony_ci			(((fb->pitches[1] >> 1) * (state->src.y1 >> 17) +
2398c2ecf20Sopenharmony_ci			(state->src.x1 >> 17)) << 1);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	dcss_dpr_addr_set(dcss->dpr, dcss_plane->ch_num, p1_ba, p2_ba,
2428c2ecf20Sopenharmony_ci			  fb->pitches[0]);
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic bool dcss_plane_needs_setup(struct drm_plane_state *state,
2468c2ecf20Sopenharmony_ci				   struct drm_plane_state *old_state)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	struct drm_framebuffer *fb = state->fb;
2498c2ecf20Sopenharmony_ci	struct drm_framebuffer *old_fb = old_state->fb;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	return state->crtc_x != old_state->crtc_x ||
2528c2ecf20Sopenharmony_ci	       state->crtc_y != old_state->crtc_y ||
2538c2ecf20Sopenharmony_ci	       state->crtc_w != old_state->crtc_w ||
2548c2ecf20Sopenharmony_ci	       state->crtc_h != old_state->crtc_h ||
2558c2ecf20Sopenharmony_ci	       state->src_x  != old_state->src_x  ||
2568c2ecf20Sopenharmony_ci	       state->src_y  != old_state->src_y  ||
2578c2ecf20Sopenharmony_ci	       state->src_w  != old_state->src_w  ||
2588c2ecf20Sopenharmony_ci	       state->src_h  != old_state->src_h  ||
2598c2ecf20Sopenharmony_ci	       fb->format->format != old_fb->format->format ||
2608c2ecf20Sopenharmony_ci	       fb->modifier  != old_fb->modifier ||
2618c2ecf20Sopenharmony_ci	       state->rotation != old_state->rotation;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic void dcss_plane_atomic_update(struct drm_plane *plane,
2658c2ecf20Sopenharmony_ci				     struct drm_plane_state *old_state)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct drm_plane_state *state = plane->state;
2688c2ecf20Sopenharmony_ci	struct dcss_plane *dcss_plane = to_dcss_plane(plane);
2698c2ecf20Sopenharmony_ci	struct dcss_dev *dcss = plane->dev->dev_private;
2708c2ecf20Sopenharmony_ci	struct drm_framebuffer *fb = state->fb;
2718c2ecf20Sopenharmony_ci	struct drm_crtc_state *crtc_state;
2728c2ecf20Sopenharmony_ci	bool modifiers_present;
2738c2ecf20Sopenharmony_ci	u32 src_w, src_h, dst_w, dst_h;
2748c2ecf20Sopenharmony_ci	struct drm_rect src, dst;
2758c2ecf20Sopenharmony_ci	bool enable = true;
2768c2ecf20Sopenharmony_ci	bool is_rotation_90_or_270;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (!fb || !state->crtc || !state->visible)
2798c2ecf20Sopenharmony_ci		return;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	crtc_state = state->crtc->state;
2828c2ecf20Sopenharmony_ci	modifiers_present = !!(fb->flags & DRM_MODE_FB_MODIFIERS);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state) &&
2858c2ecf20Sopenharmony_ci	    !dcss_plane_needs_setup(state, old_state)) {
2868c2ecf20Sopenharmony_ci		dcss_plane_atomic_set_base(dcss_plane);
2878c2ecf20Sopenharmony_ci		return;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	src = plane->state->src;
2918c2ecf20Sopenharmony_ci	dst = plane->state->dst;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	/*
2948c2ecf20Sopenharmony_ci	 * The width and height after clipping.
2958c2ecf20Sopenharmony_ci	 */
2968c2ecf20Sopenharmony_ci	src_w = drm_rect_width(&src) >> 16;
2978c2ecf20Sopenharmony_ci	src_h = drm_rect_height(&src) >> 16;
2988c2ecf20Sopenharmony_ci	dst_w = drm_rect_width(&dst);
2998c2ecf20Sopenharmony_ci	dst_h = drm_rect_height(&dst);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (plane->type == DRM_PLANE_TYPE_OVERLAY &&
3028c2ecf20Sopenharmony_ci	    modifiers_present && fb->modifier == DRM_FORMAT_MOD_LINEAR)
3038c2ecf20Sopenharmony_ci		modifiers_present = false;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	dcss_dpr_format_set(dcss->dpr, dcss_plane->ch_num, state->fb->format,
3068c2ecf20Sopenharmony_ci			    modifiers_present ? fb->modifier :
3078c2ecf20Sopenharmony_ci						DRM_FORMAT_MOD_LINEAR);
3088c2ecf20Sopenharmony_ci	dcss_dpr_set_res(dcss->dpr, dcss_plane->ch_num, src_w, src_h);
3098c2ecf20Sopenharmony_ci	dcss_dpr_set_rotation(dcss->dpr, dcss_plane->ch_num,
3108c2ecf20Sopenharmony_ci			      state->rotation);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	dcss_plane_atomic_set_base(dcss_plane);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	is_rotation_90_or_270 = state->rotation & (DRM_MODE_ROTATE_90 |
3158c2ecf20Sopenharmony_ci						   DRM_MODE_ROTATE_270);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	dcss_scaler_setup(dcss->scaler, dcss_plane->ch_num,
3188c2ecf20Sopenharmony_ci			  state->fb->format,
3198c2ecf20Sopenharmony_ci			  is_rotation_90_or_270 ? src_h : src_w,
3208c2ecf20Sopenharmony_ci			  is_rotation_90_or_270 ? src_w : src_h,
3218c2ecf20Sopenharmony_ci			  dst_w, dst_h,
3228c2ecf20Sopenharmony_ci			  drm_mode_vrefresh(&crtc_state->mode));
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
3258c2ecf20Sopenharmony_ci			       dst.x1, dst.y1, dst_w, dst_h);
3268c2ecf20Sopenharmony_ci	dcss_dtg_plane_alpha_set(dcss->dtg, dcss_plane->ch_num,
3278c2ecf20Sopenharmony_ci				 fb->format, state->alpha >> 8);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	if (!dcss_plane->ch_num && (state->alpha >> 8) == 0)
3308c2ecf20Sopenharmony_ci		enable = false;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, enable);
3338c2ecf20Sopenharmony_ci	dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, enable);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (!enable)
3368c2ecf20Sopenharmony_ci		dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
3378c2ecf20Sopenharmony_ci				       0, 0, 0, 0);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, enable);
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic void dcss_plane_atomic_disable(struct drm_plane *plane,
3438c2ecf20Sopenharmony_ci				      struct drm_plane_state *old_state)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	struct dcss_plane *dcss_plane = to_dcss_plane(plane);
3468c2ecf20Sopenharmony_ci	struct dcss_dev *dcss = plane->dev->dev_private;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, false);
3498c2ecf20Sopenharmony_ci	dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, false);
3508c2ecf20Sopenharmony_ci	dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num, 0, 0, 0, 0);
3518c2ecf20Sopenharmony_ci	dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, false);
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic const struct drm_plane_helper_funcs dcss_plane_helper_funcs = {
3558c2ecf20Sopenharmony_ci	.prepare_fb = drm_gem_fb_prepare_fb,
3568c2ecf20Sopenharmony_ci	.atomic_check = dcss_plane_atomic_check,
3578c2ecf20Sopenharmony_ci	.atomic_update = dcss_plane_atomic_update,
3588c2ecf20Sopenharmony_ci	.atomic_disable = dcss_plane_atomic_disable,
3598c2ecf20Sopenharmony_ci};
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistruct dcss_plane *dcss_plane_init(struct drm_device *drm,
3628c2ecf20Sopenharmony_ci				   unsigned int possible_crtcs,
3638c2ecf20Sopenharmony_ci				   enum drm_plane_type type,
3648c2ecf20Sopenharmony_ci				   unsigned int zpos)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	struct dcss_plane *dcss_plane;
3678c2ecf20Sopenharmony_ci	const u64 *format_modifiers = dcss_video_format_modifiers;
3688c2ecf20Sopenharmony_ci	int ret;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	if (zpos > 2)
3718c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	dcss_plane = kzalloc(sizeof(*dcss_plane), GFP_KERNEL);
3748c2ecf20Sopenharmony_ci	if (!dcss_plane) {
3758c2ecf20Sopenharmony_ci		DRM_ERROR("failed to allocate plane\n");
3768c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	if (type == DRM_PLANE_TYPE_PRIMARY)
3808c2ecf20Sopenharmony_ci		format_modifiers = dcss_graphics_format_modifiers;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	ret = drm_universal_plane_init(drm, &dcss_plane->base, possible_crtcs,
3838c2ecf20Sopenharmony_ci				       &dcss_plane_funcs, dcss_common_formats,
3848c2ecf20Sopenharmony_ci				       ARRAY_SIZE(dcss_common_formats),
3858c2ecf20Sopenharmony_ci				       format_modifiers, type, NULL);
3868c2ecf20Sopenharmony_ci	if (ret) {
3878c2ecf20Sopenharmony_ci		DRM_ERROR("failed to initialize plane\n");
3888c2ecf20Sopenharmony_ci		kfree(dcss_plane);
3898c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	drm_plane_helper_add(&dcss_plane->base, &dcss_plane_helper_funcs);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	ret = drm_plane_create_zpos_immutable_property(&dcss_plane->base, zpos);
3958c2ecf20Sopenharmony_ci	if (ret)
3968c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	drm_plane_create_rotation_property(&dcss_plane->base,
3998c2ecf20Sopenharmony_ci					   DRM_MODE_ROTATE_0,
4008c2ecf20Sopenharmony_ci					   DRM_MODE_ROTATE_0   |
4018c2ecf20Sopenharmony_ci					   DRM_MODE_ROTATE_90  |
4028c2ecf20Sopenharmony_ci					   DRM_MODE_ROTATE_180 |
4038c2ecf20Sopenharmony_ci					   DRM_MODE_ROTATE_270 |
4048c2ecf20Sopenharmony_ci					   DRM_MODE_REFLECT_X  |
4058c2ecf20Sopenharmony_ci					   DRM_MODE_REFLECT_Y);
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	dcss_plane->ch_num = zpos;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	return dcss_plane;
4108c2ecf20Sopenharmony_ci}
411