162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
462306a36Sopenharmony_ci * Author: Liviu Dudau <Liviu.Dudau@arm.com>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * ARM Mali DP plane manipulation routines.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/iommu.h>
1062306a36Sopenharmony_ci#include <linux/platform_device.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <drm/drm_atomic.h>
1362306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h>
1462306a36Sopenharmony_ci#include <drm/drm_blend.h>
1562306a36Sopenharmony_ci#include <drm/drm_drv.h>
1662306a36Sopenharmony_ci#include <drm/drm_fb_dma_helper.h>
1762306a36Sopenharmony_ci#include <drm/drm_fourcc.h>
1862306a36Sopenharmony_ci#include <drm/drm_framebuffer.h>
1962306a36Sopenharmony_ci#include <drm/drm_gem_dma_helper.h>
2062306a36Sopenharmony_ci#include <drm/drm_gem_framebuffer_helper.h>
2162306a36Sopenharmony_ci#include <drm/drm_print.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "malidp_hw.h"
2462306a36Sopenharmony_ci#include "malidp_drv.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* Layer specific register offsets */
2762306a36Sopenharmony_ci#define MALIDP_LAYER_FORMAT		0x000
2862306a36Sopenharmony_ci#define   LAYER_FORMAT_MASK		0x3f
2962306a36Sopenharmony_ci#define MALIDP_LAYER_CONTROL		0x004
3062306a36Sopenharmony_ci#define   LAYER_ENABLE			(1 << 0)
3162306a36Sopenharmony_ci#define   LAYER_FLOWCFG_MASK		7
3262306a36Sopenharmony_ci#define   LAYER_FLOWCFG(x)		(((x) & LAYER_FLOWCFG_MASK) << 1)
3362306a36Sopenharmony_ci#define     LAYER_FLOWCFG_SCALE_SE	3
3462306a36Sopenharmony_ci#define   LAYER_ROT_OFFSET		8
3562306a36Sopenharmony_ci#define   LAYER_H_FLIP			(1 << 10)
3662306a36Sopenharmony_ci#define   LAYER_V_FLIP			(1 << 11)
3762306a36Sopenharmony_ci#define   LAYER_ROT_MASK		(0xf << 8)
3862306a36Sopenharmony_ci#define   LAYER_COMP_MASK		(0x3 << 12)
3962306a36Sopenharmony_ci#define   LAYER_COMP_PIXEL		(0x3 << 12)
4062306a36Sopenharmony_ci#define   LAYER_COMP_PLANE		(0x2 << 12)
4162306a36Sopenharmony_ci#define   LAYER_PMUL_ENABLE		(0x1 << 14)
4262306a36Sopenharmony_ci#define   LAYER_ALPHA_OFFSET		(16)
4362306a36Sopenharmony_ci#define   LAYER_ALPHA_MASK		(0xff)
4462306a36Sopenharmony_ci#define   LAYER_ALPHA(x)		(((x) & LAYER_ALPHA_MASK) << LAYER_ALPHA_OFFSET)
4562306a36Sopenharmony_ci#define MALIDP_LAYER_COMPOSE		0x008
4662306a36Sopenharmony_ci#define MALIDP_LAYER_SIZE		0x00c
4762306a36Sopenharmony_ci#define   LAYER_H_VAL(x)		(((x) & 0x1fff) << 0)
4862306a36Sopenharmony_ci#define   LAYER_V_VAL(x)		(((x) & 0x1fff) << 16)
4962306a36Sopenharmony_ci#define MALIDP_LAYER_COMP_SIZE		0x010
5062306a36Sopenharmony_ci#define MALIDP_LAYER_OFFSET		0x014
5162306a36Sopenharmony_ci#define MALIDP550_LS_ENABLE		0x01c
5262306a36Sopenharmony_ci#define MALIDP550_LS_R1_IN_SIZE		0x020
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define MODIFIERS_COUNT_MAX		15
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/*
5762306a36Sopenharmony_ci * This 4-entry look-up-table is used to determine the full 8-bit alpha value
5862306a36Sopenharmony_ci * for formats with 1- or 2-bit alpha channels.
5962306a36Sopenharmony_ci * We set it to give 100%/0% opacity for 1-bit formats and 100%/66%/33%/0%
6062306a36Sopenharmony_ci * opacity for 2-bit formats.
6162306a36Sopenharmony_ci */
6262306a36Sopenharmony_ci#define MALIDP_ALPHA_LUT 0xffaa5500
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/* page sizes the MMU prefetcher can support */
6562306a36Sopenharmony_ci#define MALIDP_MMU_PREFETCH_PARTIAL_PGSIZES	(SZ_4K | SZ_64K)
6662306a36Sopenharmony_ci#define MALIDP_MMU_PREFETCH_FULL_PGSIZES	(SZ_1M | SZ_2M)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* readahead for partial-frame prefetch */
6962306a36Sopenharmony_ci#define MALIDP_MMU_PREFETCH_READAHEAD		8
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/*
7262306a36Sopenharmony_ci * Replicate what the default ->reset hook does: free the state pointer and
7362306a36Sopenharmony_ci * allocate a new empty object. We just need enough space to store
7462306a36Sopenharmony_ci * a malidp_plane_state instead of a drm_plane_state.
7562306a36Sopenharmony_ci */
7662306a36Sopenharmony_cistatic void malidp_plane_reset(struct drm_plane *plane)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct malidp_plane_state *state = to_malidp_plane_state(plane->state);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	if (state)
8162306a36Sopenharmony_ci		__drm_atomic_helper_plane_destroy_state(&state->base);
8262306a36Sopenharmony_ci	kfree(state);
8362306a36Sopenharmony_ci	plane->state = NULL;
8462306a36Sopenharmony_ci	state = kzalloc(sizeof(*state), GFP_KERNEL);
8562306a36Sopenharmony_ci	if (state)
8662306a36Sopenharmony_ci		__drm_atomic_helper_plane_reset(plane, &state->base);
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic struct
9062306a36Sopenharmony_cidrm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct malidp_plane_state *state, *m_state;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (!plane->state)
9562306a36Sopenharmony_ci		return NULL;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	state = kmalloc(sizeof(*state), GFP_KERNEL);
9862306a36Sopenharmony_ci	if (!state)
9962306a36Sopenharmony_ci		return NULL;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	m_state = to_malidp_plane_state(plane->state);
10262306a36Sopenharmony_ci	__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
10362306a36Sopenharmony_ci	state->rotmem_size = m_state->rotmem_size;
10462306a36Sopenharmony_ci	state->format = m_state->format;
10562306a36Sopenharmony_ci	state->n_planes = m_state->n_planes;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	state->mmu_prefetch_mode = m_state->mmu_prefetch_mode;
10862306a36Sopenharmony_ci	state->mmu_prefetch_pgsize = m_state->mmu_prefetch_pgsize;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	return &state->base;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic void malidp_destroy_plane_state(struct drm_plane *plane,
11462306a36Sopenharmony_ci				       struct drm_plane_state *state)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	struct malidp_plane_state *m_state = to_malidp_plane_state(state);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	__drm_atomic_helper_plane_destroy_state(state);
11962306a36Sopenharmony_ci	kfree(m_state);
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic const char * const prefetch_mode_names[] = {
12362306a36Sopenharmony_ci	[MALIDP_PREFETCH_MODE_NONE] = "MMU_PREFETCH_NONE",
12462306a36Sopenharmony_ci	[MALIDP_PREFETCH_MODE_PARTIAL] = "MMU_PREFETCH_PARTIAL",
12562306a36Sopenharmony_ci	[MALIDP_PREFETCH_MODE_FULL] = "MMU_PREFETCH_FULL",
12662306a36Sopenharmony_ci};
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic void malidp_plane_atomic_print_state(struct drm_printer *p,
12962306a36Sopenharmony_ci					    const struct drm_plane_state *state)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	struct malidp_plane_state *ms = to_malidp_plane_state(state);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	drm_printf(p, "\trotmem_size=%u\n", ms->rotmem_size);
13462306a36Sopenharmony_ci	drm_printf(p, "\tformat_id=%u\n", ms->format);
13562306a36Sopenharmony_ci	drm_printf(p, "\tn_planes=%u\n", ms->n_planes);
13662306a36Sopenharmony_ci	drm_printf(p, "\tmmu_prefetch_mode=%s\n",
13762306a36Sopenharmony_ci		   prefetch_mode_names[ms->mmu_prefetch_mode]);
13862306a36Sopenharmony_ci	drm_printf(p, "\tmmu_prefetch_pgsize=%d\n", ms->mmu_prefetch_pgsize);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cibool malidp_format_mod_supported(struct drm_device *drm,
14262306a36Sopenharmony_ci				 u32 format, u64 modifier)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	const struct drm_format_info *info;
14562306a36Sopenharmony_ci	const u64 *modifiers;
14662306a36Sopenharmony_ci	struct malidp_drm *malidp = drm_to_malidp(drm);
14762306a36Sopenharmony_ci	const struct malidp_hw_regmap *map = &malidp->dev->hw->map;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID))
15062306a36Sopenharmony_ci		return false;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	/* Some pixel formats are supported without any modifier */
15362306a36Sopenharmony_ci	if (modifier == DRM_FORMAT_MOD_LINEAR) {
15462306a36Sopenharmony_ci		/*
15562306a36Sopenharmony_ci		 * However these pixel formats need to be supported with
15662306a36Sopenharmony_ci		 * modifiers only
15762306a36Sopenharmony_ci		 */
15862306a36Sopenharmony_ci		return !malidp_hw_format_is_afbc_only(format);
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (!fourcc_mod_is_vendor(modifier, ARM)) {
16262306a36Sopenharmony_ci		DRM_ERROR("Unknown modifier (not Arm)\n");
16362306a36Sopenharmony_ci		return false;
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	if (modifier &
16762306a36Sopenharmony_ci	    ~DRM_FORMAT_MOD_ARM_AFBC(AFBC_MOD_VALID_BITS)) {
16862306a36Sopenharmony_ci		DRM_DEBUG_KMS("Unsupported modifiers\n");
16962306a36Sopenharmony_ci		return false;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	modifiers = malidp_format_modifiers;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	/* SPLIT buffers must use SPARSE layout */
17562306a36Sopenharmony_ci	if (WARN_ON_ONCE((modifier & AFBC_SPLIT) && !(modifier & AFBC_SPARSE)))
17662306a36Sopenharmony_ci		return false;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/* CBR only applies to YUV formats, where YTR should be always 0 */
17962306a36Sopenharmony_ci	if (WARN_ON_ONCE((modifier & AFBC_CBR) && (modifier & AFBC_YTR)))
18062306a36Sopenharmony_ci		return false;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	while (*modifiers != DRM_FORMAT_MOD_INVALID) {
18362306a36Sopenharmony_ci		if (*modifiers == modifier)
18462306a36Sopenharmony_ci			break;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci		modifiers++;
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	/* return false, if the modifier was not found */
19062306a36Sopenharmony_ci	if (*modifiers == DRM_FORMAT_MOD_INVALID) {
19162306a36Sopenharmony_ci		DRM_DEBUG_KMS("Unsupported modifier\n");
19262306a36Sopenharmony_ci		return false;
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	info = drm_format_info(format);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (info->num_planes != 1) {
19862306a36Sopenharmony_ci		DRM_DEBUG_KMS("AFBC buffers expect one plane\n");
19962306a36Sopenharmony_ci		return false;
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	if (malidp_hw_format_is_linear_only(format) == true) {
20362306a36Sopenharmony_ci		DRM_DEBUG_KMS("Given format (0x%x) is supported is linear mode only\n",
20462306a36Sopenharmony_ci			      format);
20562306a36Sopenharmony_ci		return false;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/*
20962306a36Sopenharmony_ci	 * RGB formats need to provide YTR modifier and YUV formats should not
21062306a36Sopenharmony_ci	 * provide YTR modifier.
21162306a36Sopenharmony_ci	 */
21262306a36Sopenharmony_ci	if (!(info->is_yuv) != !!(modifier & AFBC_FORMAT_MOD_YTR)) {
21362306a36Sopenharmony_ci		DRM_DEBUG_KMS("AFBC_FORMAT_MOD_YTR is %s for %s formats\n",
21462306a36Sopenharmony_ci			      info->is_yuv ? "disallowed" : "mandatory",
21562306a36Sopenharmony_ci			      info->is_yuv ? "YUV" : "RGB");
21662306a36Sopenharmony_ci		return false;
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (modifier & AFBC_SPLIT) {
22062306a36Sopenharmony_ci		if (!info->is_yuv) {
22162306a36Sopenharmony_ci			if (info->cpp[0] <= 2) {
22262306a36Sopenharmony_ci				DRM_DEBUG_KMS("RGB formats <= 16bpp are not supported with SPLIT\n");
22362306a36Sopenharmony_ci				return false;
22462306a36Sopenharmony_ci			}
22562306a36Sopenharmony_ci		}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci		if ((info->hsub != 1) || (info->vsub != 1)) {
22862306a36Sopenharmony_ci			if (!(format == DRM_FORMAT_YUV420_10BIT &&
22962306a36Sopenharmony_ci			      (map->features & MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT))) {
23062306a36Sopenharmony_ci				DRM_DEBUG_KMS("Formats which are sub-sampled should never be split\n");
23162306a36Sopenharmony_ci				return false;
23262306a36Sopenharmony_ci			}
23362306a36Sopenharmony_ci		}
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	if (modifier & AFBC_CBR) {
23762306a36Sopenharmony_ci		if ((info->hsub == 1) || (info->vsub == 1)) {
23862306a36Sopenharmony_ci			DRM_DEBUG_KMS("Formats which are not sub-sampled should not have CBR set\n");
23962306a36Sopenharmony_ci			return false;
24062306a36Sopenharmony_ci		}
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	return true;
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic bool malidp_format_mod_supported_per_plane(struct drm_plane *plane,
24762306a36Sopenharmony_ci						  u32 format, u64 modifier)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	return malidp_format_mod_supported(plane->dev, format, modifier);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic const struct drm_plane_funcs malidp_de_plane_funcs = {
25362306a36Sopenharmony_ci	.update_plane = drm_atomic_helper_update_plane,
25462306a36Sopenharmony_ci	.disable_plane = drm_atomic_helper_disable_plane,
25562306a36Sopenharmony_ci	.reset = malidp_plane_reset,
25662306a36Sopenharmony_ci	.atomic_duplicate_state = malidp_duplicate_plane_state,
25762306a36Sopenharmony_ci	.atomic_destroy_state = malidp_destroy_plane_state,
25862306a36Sopenharmony_ci	.atomic_print_state = malidp_plane_atomic_print_state,
25962306a36Sopenharmony_ci	.format_mod_supported = malidp_format_mod_supported_per_plane,
26062306a36Sopenharmony_ci};
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic int malidp_se_check_scaling(struct malidp_plane *mp,
26362306a36Sopenharmony_ci				   struct drm_plane_state *state)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct drm_crtc_state *crtc_state =
26662306a36Sopenharmony_ci		drm_atomic_get_existing_crtc_state(state->state, state->crtc);
26762306a36Sopenharmony_ci	struct malidp_crtc_state *mc;
26862306a36Sopenharmony_ci	u32 src_w, src_h;
26962306a36Sopenharmony_ci	int ret;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (!crtc_state)
27262306a36Sopenharmony_ci		return -EINVAL;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	mc = to_malidp_crtc_state(crtc_state);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	ret = drm_atomic_helper_check_plane_state(state, crtc_state,
27762306a36Sopenharmony_ci						  0, INT_MAX, true, true);
27862306a36Sopenharmony_ci	if (ret)
27962306a36Sopenharmony_ci		return ret;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	if (state->rotation & MALIDP_ROTATED_MASK) {
28262306a36Sopenharmony_ci		src_w = state->src_h >> 16;
28362306a36Sopenharmony_ci		src_h = state->src_w >> 16;
28462306a36Sopenharmony_ci	} else {
28562306a36Sopenharmony_ci		src_w = state->src_w >> 16;
28662306a36Sopenharmony_ci		src_h = state->src_h >> 16;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if ((state->crtc_w == src_w) && (state->crtc_h == src_h)) {
29062306a36Sopenharmony_ci		/* Scaling not necessary for this plane. */
29162306a36Sopenharmony_ci		mc->scaled_planes_mask &= ~(mp->layer->id);
29262306a36Sopenharmony_ci		return 0;
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (mp->layer->id & (DE_SMART | DE_GRAPHICS2))
29662306a36Sopenharmony_ci		return -EINVAL;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	mc->scaled_planes_mask |= mp->layer->id;
29962306a36Sopenharmony_ci	/* Defer scaling requirements calculation to the crtc check. */
30062306a36Sopenharmony_ci	return 0;
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic u32 malidp_get_pgsize_bitmap(struct malidp_plane *mp)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	struct iommu_domain *mmu_dom;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	mmu_dom = iommu_get_domain_for_dev(mp->base.dev->dev);
30862306a36Sopenharmony_ci	if (mmu_dom)
30962306a36Sopenharmony_ci		return mmu_dom->pgsize_bitmap;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	return 0;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci/*
31562306a36Sopenharmony_ci * Check if the framebuffer is entirely made up of pages at least pgsize in
31662306a36Sopenharmony_ci * size. Only a heuristic: assumes that each scatterlist entry has been aligned
31762306a36Sopenharmony_ci * to the largest page size smaller than its length and that the MMU maps to
31862306a36Sopenharmony_ci * the largest page size possible.
31962306a36Sopenharmony_ci */
32062306a36Sopenharmony_cistatic bool malidp_check_pages_threshold(struct malidp_plane_state *ms,
32162306a36Sopenharmony_ci					 u32 pgsize)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	int i;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	for (i = 0; i < ms->n_planes; i++) {
32662306a36Sopenharmony_ci		struct drm_gem_object *obj;
32762306a36Sopenharmony_ci		struct drm_gem_dma_object *dma_obj;
32862306a36Sopenharmony_ci		struct sg_table *sgt;
32962306a36Sopenharmony_ci		struct scatterlist *sgl;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci		obj = drm_gem_fb_get_obj(ms->base.fb, i);
33262306a36Sopenharmony_ci		dma_obj = to_drm_gem_dma_obj(obj);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		if (dma_obj->sgt)
33562306a36Sopenharmony_ci			sgt = dma_obj->sgt;
33662306a36Sopenharmony_ci		else
33762306a36Sopenharmony_ci			sgt = obj->funcs->get_sg_table(obj);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci		if (IS_ERR(sgt))
34062306a36Sopenharmony_ci			return false;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci		sgl = sgt->sgl;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci		while (sgl) {
34562306a36Sopenharmony_ci			if (sgl->length < pgsize) {
34662306a36Sopenharmony_ci				if (!dma_obj->sgt)
34762306a36Sopenharmony_ci					kfree(sgt);
34862306a36Sopenharmony_ci				return false;
34962306a36Sopenharmony_ci			}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci			sgl = sg_next(sgl);
35262306a36Sopenharmony_ci		}
35362306a36Sopenharmony_ci		if (!dma_obj->sgt)
35462306a36Sopenharmony_ci			kfree(sgt);
35562306a36Sopenharmony_ci	}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	return true;
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci/*
36162306a36Sopenharmony_ci * Check if it is possible to enable partial-frame MMU prefetch given the
36262306a36Sopenharmony_ci * current format, AFBC state and rotation.
36362306a36Sopenharmony_ci */
36462306a36Sopenharmony_cistatic bool malidp_partial_prefetch_supported(u32 format, u64 modifier,
36562306a36Sopenharmony_ci					      unsigned int rotation)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	bool afbc, sparse;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	/* rotation and horizontal flip not supported for partial prefetch */
37062306a36Sopenharmony_ci	if (rotation & (DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_180 |
37162306a36Sopenharmony_ci			DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X))
37262306a36Sopenharmony_ci		return false;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	afbc = modifier & DRM_FORMAT_MOD_ARM_AFBC(0);
37562306a36Sopenharmony_ci	sparse = modifier & AFBC_FORMAT_MOD_SPARSE;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	switch (format) {
37862306a36Sopenharmony_ci	case DRM_FORMAT_ARGB2101010:
37962306a36Sopenharmony_ci	case DRM_FORMAT_RGBA1010102:
38062306a36Sopenharmony_ci	case DRM_FORMAT_BGRA1010102:
38162306a36Sopenharmony_ci	case DRM_FORMAT_ARGB8888:
38262306a36Sopenharmony_ci	case DRM_FORMAT_RGBA8888:
38362306a36Sopenharmony_ci	case DRM_FORMAT_BGRA8888:
38462306a36Sopenharmony_ci	case DRM_FORMAT_XRGB8888:
38562306a36Sopenharmony_ci	case DRM_FORMAT_XBGR8888:
38662306a36Sopenharmony_ci	case DRM_FORMAT_RGBX8888:
38762306a36Sopenharmony_ci	case DRM_FORMAT_BGRX8888:
38862306a36Sopenharmony_ci	case DRM_FORMAT_RGB888:
38962306a36Sopenharmony_ci	case DRM_FORMAT_RGBA5551:
39062306a36Sopenharmony_ci	case DRM_FORMAT_RGB565:
39162306a36Sopenharmony_ci		/* always supported */
39262306a36Sopenharmony_ci		return true;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	case DRM_FORMAT_ABGR2101010:
39562306a36Sopenharmony_ci	case DRM_FORMAT_ABGR8888:
39662306a36Sopenharmony_ci	case DRM_FORMAT_ABGR1555:
39762306a36Sopenharmony_ci	case DRM_FORMAT_BGR565:
39862306a36Sopenharmony_ci		/* supported, but if AFBC then must be sparse mode */
39962306a36Sopenharmony_ci		return (!afbc) || (afbc && sparse);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	case DRM_FORMAT_BGR888:
40262306a36Sopenharmony_ci		/* supported, but not for AFBC */
40362306a36Sopenharmony_ci		return !afbc;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	case DRM_FORMAT_YUYV:
40662306a36Sopenharmony_ci	case DRM_FORMAT_UYVY:
40762306a36Sopenharmony_ci	case DRM_FORMAT_NV12:
40862306a36Sopenharmony_ci	case DRM_FORMAT_YUV420:
40962306a36Sopenharmony_ci		/* not supported */
41062306a36Sopenharmony_ci		return false;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	default:
41362306a36Sopenharmony_ci		return false;
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci/*
41862306a36Sopenharmony_ci * Select the preferred MMU prefetch mode. Full-frame prefetch is preferred as
41962306a36Sopenharmony_ci * long as the framebuffer is all large pages. Otherwise partial-frame prefetch
42062306a36Sopenharmony_ci * is selected as long as it is supported for the current format. The selected
42162306a36Sopenharmony_ci * page size for prefetch is returned in pgsize_bitmap.
42262306a36Sopenharmony_ci */
42362306a36Sopenharmony_cistatic enum mmu_prefetch_mode malidp_mmu_prefetch_select_mode
42462306a36Sopenharmony_ci		(struct malidp_plane_state *ms,	u32 *pgsize_bitmap)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	u32 pgsizes;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	/* get the full-frame prefetch page size(s) supported by the MMU */
42962306a36Sopenharmony_ci	pgsizes = *pgsize_bitmap & MALIDP_MMU_PREFETCH_FULL_PGSIZES;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	while (pgsizes) {
43262306a36Sopenharmony_ci		u32 largest_pgsize = 1 << __fls(pgsizes);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		if (malidp_check_pages_threshold(ms, largest_pgsize)) {
43562306a36Sopenharmony_ci			*pgsize_bitmap = largest_pgsize;
43662306a36Sopenharmony_ci			return MALIDP_PREFETCH_MODE_FULL;
43762306a36Sopenharmony_ci		}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci		pgsizes -= largest_pgsize;
44062306a36Sopenharmony_ci	}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	/* get the partial-frame prefetch page size(s) supported by the MMU */
44362306a36Sopenharmony_ci	pgsizes = *pgsize_bitmap & MALIDP_MMU_PREFETCH_PARTIAL_PGSIZES;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	if (malidp_partial_prefetch_supported(ms->base.fb->format->format,
44662306a36Sopenharmony_ci					      ms->base.fb->modifier,
44762306a36Sopenharmony_ci					      ms->base.rotation)) {
44862306a36Sopenharmony_ci		/* partial prefetch using the smallest page size */
44962306a36Sopenharmony_ci		*pgsize_bitmap = 1 << __ffs(pgsizes);
45062306a36Sopenharmony_ci		return MALIDP_PREFETCH_MODE_PARTIAL;
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci	*pgsize_bitmap = 0;
45362306a36Sopenharmony_ci	return MALIDP_PREFETCH_MODE_NONE;
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic u32 malidp_calc_mmu_control_value(enum mmu_prefetch_mode mode,
45762306a36Sopenharmony_ci					 u8 readahead, u8 n_planes, u32 pgsize)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	u32 mmu_ctrl = 0;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	if (mode != MALIDP_PREFETCH_MODE_NONE) {
46262306a36Sopenharmony_ci		mmu_ctrl |= MALIDP_MMU_CTRL_EN;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci		if (mode == MALIDP_PREFETCH_MODE_PARTIAL) {
46562306a36Sopenharmony_ci			mmu_ctrl |= MALIDP_MMU_CTRL_MODE;
46662306a36Sopenharmony_ci			mmu_ctrl |= MALIDP_MMU_CTRL_PP_NUM_REQ(readahead);
46762306a36Sopenharmony_ci		}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci		if (pgsize == SZ_64K || pgsize == SZ_2M) {
47062306a36Sopenharmony_ci			int i;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci			for (i = 0; i < n_planes; i++)
47362306a36Sopenharmony_ci				mmu_ctrl |= MALIDP_MMU_CTRL_PX_PS(i);
47462306a36Sopenharmony_ci		}
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	return mmu_ctrl;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic void malidp_de_prefetch_settings(struct malidp_plane *mp,
48162306a36Sopenharmony_ci					struct malidp_plane_state *ms)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	if (!mp->layer->mmu_ctrl_offset)
48462306a36Sopenharmony_ci		return;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	/* get the page sizes supported by the MMU */
48762306a36Sopenharmony_ci	ms->mmu_prefetch_pgsize = malidp_get_pgsize_bitmap(mp);
48862306a36Sopenharmony_ci	ms->mmu_prefetch_mode  =
48962306a36Sopenharmony_ci		malidp_mmu_prefetch_select_mode(ms, &ms->mmu_prefetch_pgsize);
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic int malidp_de_plane_check(struct drm_plane *plane,
49362306a36Sopenharmony_ci				 struct drm_atomic_state *state)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
49662306a36Sopenharmony_ci										 plane);
49762306a36Sopenharmony_ci	struct malidp_plane *mp = to_malidp_plane(plane);
49862306a36Sopenharmony_ci	struct malidp_plane_state *ms = to_malidp_plane_state(new_plane_state);
49962306a36Sopenharmony_ci	bool rotated = new_plane_state->rotation & MALIDP_ROTATED_MASK;
50062306a36Sopenharmony_ci	struct drm_framebuffer *fb;
50162306a36Sopenharmony_ci	u16 pixel_alpha = new_plane_state->pixel_blend_mode;
50262306a36Sopenharmony_ci	int i, ret;
50362306a36Sopenharmony_ci	unsigned int block_w, block_h;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	if (!new_plane_state->crtc || WARN_ON(!new_plane_state->fb))
50662306a36Sopenharmony_ci		return 0;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	fb = new_plane_state->fb;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	ms->format = malidp_hw_get_format_id(&mp->hwdev->hw->map,
51162306a36Sopenharmony_ci					     mp->layer->id, fb->format->format,
51262306a36Sopenharmony_ci					     !!fb->modifier);
51362306a36Sopenharmony_ci	if (ms->format == MALIDP_INVALID_FORMAT_ID)
51462306a36Sopenharmony_ci		return -EINVAL;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	ms->n_planes = fb->format->num_planes;
51762306a36Sopenharmony_ci	for (i = 0; i < ms->n_planes; i++) {
51862306a36Sopenharmony_ci		u8 alignment = malidp_hw_get_pitch_align(mp->hwdev, rotated);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci		if (((fb->pitches[i] * drm_format_info_block_height(fb->format, i))
52162306a36Sopenharmony_ci				& (alignment - 1)) && !(fb->modifier)) {
52262306a36Sopenharmony_ci			DRM_DEBUG_KMS("Invalid pitch %u for plane %d\n",
52362306a36Sopenharmony_ci				      fb->pitches[i], i);
52462306a36Sopenharmony_ci			return -EINVAL;
52562306a36Sopenharmony_ci		}
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	block_w = drm_format_info_block_width(fb->format, 0);
52962306a36Sopenharmony_ci	block_h = drm_format_info_block_height(fb->format, 0);
53062306a36Sopenharmony_ci	if (fb->width % block_w || fb->height % block_h) {
53162306a36Sopenharmony_ci		DRM_DEBUG_KMS("Buffer width/height needs to be a multiple of tile sizes");
53262306a36Sopenharmony_ci		return -EINVAL;
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci	if ((new_plane_state->src_x >> 16) % block_w || (new_plane_state->src_y >> 16) % block_h) {
53562306a36Sopenharmony_ci		DRM_DEBUG_KMS("Plane src_x/src_y needs to be a multiple of tile sizes");
53662306a36Sopenharmony_ci		return -EINVAL;
53762306a36Sopenharmony_ci	}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	if ((new_plane_state->crtc_w > mp->hwdev->max_line_size) ||
54062306a36Sopenharmony_ci	    (new_plane_state->crtc_h > mp->hwdev->max_line_size) ||
54162306a36Sopenharmony_ci	    (new_plane_state->crtc_w < mp->hwdev->min_line_size) ||
54262306a36Sopenharmony_ci	    (new_plane_state->crtc_h < mp->hwdev->min_line_size))
54362306a36Sopenharmony_ci		return -EINVAL;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	/*
54662306a36Sopenharmony_ci	 * DP550/650 video layers can accept 3 plane formats only if
54762306a36Sopenharmony_ci	 * fb->pitches[1] == fb->pitches[2] since they don't have a
54862306a36Sopenharmony_ci	 * third plane stride register.
54962306a36Sopenharmony_ci	 */
55062306a36Sopenharmony_ci	if (ms->n_planes == 3 &&
55162306a36Sopenharmony_ci	    !(mp->hwdev->hw->features & MALIDP_DEVICE_LV_HAS_3_STRIDES) &&
55262306a36Sopenharmony_ci	    (new_plane_state->fb->pitches[1] != new_plane_state->fb->pitches[2]))
55362306a36Sopenharmony_ci		return -EINVAL;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	ret = malidp_se_check_scaling(mp, new_plane_state);
55662306a36Sopenharmony_ci	if (ret)
55762306a36Sopenharmony_ci		return ret;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	/* validate the rotation constraints for each layer */
56062306a36Sopenharmony_ci	if (new_plane_state->rotation != DRM_MODE_ROTATE_0) {
56162306a36Sopenharmony_ci		if (mp->layer->rot == ROTATE_NONE)
56262306a36Sopenharmony_ci			return -EINVAL;
56362306a36Sopenharmony_ci		if ((mp->layer->rot == ROTATE_COMPRESSED) && !(fb->modifier))
56462306a36Sopenharmony_ci			return -EINVAL;
56562306a36Sopenharmony_ci		/*
56662306a36Sopenharmony_ci		 * packed RGB888 / BGR888 can't be rotated or flipped
56762306a36Sopenharmony_ci		 * unless they are stored in a compressed way
56862306a36Sopenharmony_ci		 */
56962306a36Sopenharmony_ci		if ((fb->format->format == DRM_FORMAT_RGB888 ||
57062306a36Sopenharmony_ci		     fb->format->format == DRM_FORMAT_BGR888) && !(fb->modifier))
57162306a36Sopenharmony_ci			return -EINVAL;
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	/* SMART layer does not support AFBC */
57562306a36Sopenharmony_ci	if (mp->layer->id == DE_SMART && fb->modifier) {
57662306a36Sopenharmony_ci		DRM_ERROR("AFBC framebuffer not supported in SMART layer");
57762306a36Sopenharmony_ci		return -EINVAL;
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	ms->rotmem_size = 0;
58162306a36Sopenharmony_ci	if (new_plane_state->rotation & MALIDP_ROTATED_MASK) {
58262306a36Sopenharmony_ci		int val;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci		val = mp->hwdev->hw->rotmem_required(mp->hwdev, new_plane_state->crtc_w,
58562306a36Sopenharmony_ci						     new_plane_state->crtc_h,
58662306a36Sopenharmony_ci						     fb->format->format,
58762306a36Sopenharmony_ci						     !!(fb->modifier));
58862306a36Sopenharmony_ci		if (val < 0)
58962306a36Sopenharmony_ci			return val;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci		ms->rotmem_size = val;
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	/* HW can't support plane + pixel blending */
59562306a36Sopenharmony_ci	if ((new_plane_state->alpha != DRM_BLEND_ALPHA_OPAQUE) &&
59662306a36Sopenharmony_ci	    (pixel_alpha != DRM_MODE_BLEND_PIXEL_NONE) &&
59762306a36Sopenharmony_ci	    fb->format->has_alpha)
59862306a36Sopenharmony_ci		return -EINVAL;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	malidp_de_prefetch_settings(mp, ms);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	return 0;
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_cistatic void malidp_de_set_plane_pitches(struct malidp_plane *mp,
60662306a36Sopenharmony_ci					int num_planes, unsigned int pitches[3])
60762306a36Sopenharmony_ci{
60862306a36Sopenharmony_ci	int i;
60962306a36Sopenharmony_ci	int num_strides = num_planes;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	if (!mp->layer->stride_offset)
61262306a36Sopenharmony_ci		return;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	if (num_planes == 3)
61562306a36Sopenharmony_ci		num_strides = (mp->hwdev->hw->features &
61662306a36Sopenharmony_ci			       MALIDP_DEVICE_LV_HAS_3_STRIDES) ? 3 : 2;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	/*
61962306a36Sopenharmony_ci	 * The drm convention for pitch is that it needs to cover width * cpp,
62062306a36Sopenharmony_ci	 * but our hardware wants the pitch/stride to cover all rows included
62162306a36Sopenharmony_ci	 * in a tile.
62262306a36Sopenharmony_ci	 */
62362306a36Sopenharmony_ci	for (i = 0; i < num_strides; ++i) {
62462306a36Sopenharmony_ci		unsigned int block_h = drm_format_info_block_height(mp->base.state->fb->format, i);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci		malidp_hw_write(mp->hwdev, pitches[i] * block_h,
62762306a36Sopenharmony_ci				mp->layer->base +
62862306a36Sopenharmony_ci				mp->layer->stride_offset + i * 4);
62962306a36Sopenharmony_ci	}
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_cistatic const s16
63362306a36Sopenharmony_cimalidp_yuv2rgb_coeffs[][DRM_COLOR_RANGE_MAX][MALIDP_COLORADJ_NUM_COEFFS] = {
63462306a36Sopenharmony_ci	[DRM_COLOR_YCBCR_BT601][DRM_COLOR_YCBCR_LIMITED_RANGE] = {
63562306a36Sopenharmony_ci		1192,    0, 1634,
63662306a36Sopenharmony_ci		1192, -401, -832,
63762306a36Sopenharmony_ci		1192, 2066,    0,
63862306a36Sopenharmony_ci		  64,  512,  512
63962306a36Sopenharmony_ci	},
64062306a36Sopenharmony_ci	[DRM_COLOR_YCBCR_BT601][DRM_COLOR_YCBCR_FULL_RANGE] = {
64162306a36Sopenharmony_ci		1024,    0, 1436,
64262306a36Sopenharmony_ci		1024, -352, -731,
64362306a36Sopenharmony_ci		1024, 1815,    0,
64462306a36Sopenharmony_ci		   0,  512,  512
64562306a36Sopenharmony_ci	},
64662306a36Sopenharmony_ci	[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE] = {
64762306a36Sopenharmony_ci		1192,    0, 1836,
64862306a36Sopenharmony_ci		1192, -218, -546,
64962306a36Sopenharmony_ci		1192, 2163,    0,
65062306a36Sopenharmony_ci		  64,  512,  512
65162306a36Sopenharmony_ci	},
65262306a36Sopenharmony_ci	[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_FULL_RANGE] = {
65362306a36Sopenharmony_ci		1024,    0, 1613,
65462306a36Sopenharmony_ci		1024, -192, -479,
65562306a36Sopenharmony_ci		1024, 1900,    0,
65662306a36Sopenharmony_ci		   0,  512,  512
65762306a36Sopenharmony_ci	},
65862306a36Sopenharmony_ci	[DRM_COLOR_YCBCR_BT2020][DRM_COLOR_YCBCR_LIMITED_RANGE] = {
65962306a36Sopenharmony_ci		1024,    0, 1476,
66062306a36Sopenharmony_ci		1024, -165, -572,
66162306a36Sopenharmony_ci		1024, 1884,    0,
66262306a36Sopenharmony_ci		   0,  512,  512
66362306a36Sopenharmony_ci	},
66462306a36Sopenharmony_ci	[DRM_COLOR_YCBCR_BT2020][DRM_COLOR_YCBCR_FULL_RANGE] = {
66562306a36Sopenharmony_ci		1024,    0, 1510,
66662306a36Sopenharmony_ci		1024, -168, -585,
66762306a36Sopenharmony_ci		1024, 1927,    0,
66862306a36Sopenharmony_ci		   0,  512,  512
66962306a36Sopenharmony_ci	}
67062306a36Sopenharmony_ci};
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cistatic void malidp_de_set_color_encoding(struct malidp_plane *plane,
67362306a36Sopenharmony_ci					 enum drm_color_encoding enc,
67462306a36Sopenharmony_ci					 enum drm_color_range range)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	unsigned int i;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
67962306a36Sopenharmony_ci		/* coefficients are signed, two's complement values */
68062306a36Sopenharmony_ci		malidp_hw_write(plane->hwdev, malidp_yuv2rgb_coeffs[enc][range][i],
68162306a36Sopenharmony_ci				plane->layer->base + plane->layer->yuv2rgb_offset +
68262306a36Sopenharmony_ci				i * 4);
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_cistatic void malidp_de_set_mmu_control(struct malidp_plane *mp,
68762306a36Sopenharmony_ci				      struct malidp_plane_state *ms)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	u32 mmu_ctrl;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	/* check hardware supports MMU prefetch */
69262306a36Sopenharmony_ci	if (!mp->layer->mmu_ctrl_offset)
69362306a36Sopenharmony_ci		return;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	mmu_ctrl = malidp_calc_mmu_control_value(ms->mmu_prefetch_mode,
69662306a36Sopenharmony_ci						 MALIDP_MMU_PREFETCH_READAHEAD,
69762306a36Sopenharmony_ci						 ms->n_planes,
69862306a36Sopenharmony_ci						 ms->mmu_prefetch_pgsize);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	malidp_hw_write(mp->hwdev, mmu_ctrl,
70162306a36Sopenharmony_ci			mp->layer->base + mp->layer->mmu_ctrl_offset);
70262306a36Sopenharmony_ci}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_cistatic void malidp_set_plane_base_addr(struct drm_framebuffer *fb,
70562306a36Sopenharmony_ci				       struct malidp_plane *mp,
70662306a36Sopenharmony_ci				       int plane_index)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	dma_addr_t dma_addr;
70962306a36Sopenharmony_ci	u16 ptr;
71062306a36Sopenharmony_ci	struct drm_plane *plane = &mp->base;
71162306a36Sopenharmony_ci	bool afbc = fb->modifier ? true : false;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	ptr = mp->layer->ptr + (plane_index << 4);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	/*
71662306a36Sopenharmony_ci	 * drm_fb_dma_get_gem_addr() alters the physical base address of the
71762306a36Sopenharmony_ci	 * framebuffer as per the plane's src_x, src_y co-ordinates (ie to
71862306a36Sopenharmony_ci	 * take care of source cropping).
71962306a36Sopenharmony_ci	 * For AFBC, this is not needed as the cropping is handled by _AD_CROP_H
72062306a36Sopenharmony_ci	 * and _AD_CROP_V registers.
72162306a36Sopenharmony_ci	 */
72262306a36Sopenharmony_ci	if (!afbc) {
72362306a36Sopenharmony_ci		dma_addr = drm_fb_dma_get_gem_addr(fb, plane->state,
72462306a36Sopenharmony_ci						   plane_index);
72562306a36Sopenharmony_ci	} else {
72662306a36Sopenharmony_ci		struct drm_gem_dma_object *obj;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci		obj = drm_fb_dma_get_gem_obj(fb, plane_index);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci		if (WARN_ON(!obj))
73162306a36Sopenharmony_ci			return;
73262306a36Sopenharmony_ci		dma_addr = obj->dma_addr;
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	malidp_hw_write(mp->hwdev, lower_32_bits(dma_addr), ptr);
73662306a36Sopenharmony_ci	malidp_hw_write(mp->hwdev, upper_32_bits(dma_addr), ptr + 4);
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_cistatic void malidp_de_set_plane_afbc(struct drm_plane *plane)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	struct malidp_plane *mp;
74262306a36Sopenharmony_ci	u32 src_w, src_h, val = 0, src_x, src_y;
74362306a36Sopenharmony_ci	struct drm_framebuffer *fb = plane->state->fb;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	mp = to_malidp_plane(plane);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	/* no afbc_decoder_offset means AFBC is not supported on this plane */
74862306a36Sopenharmony_ci	if (!mp->layer->afbc_decoder_offset)
74962306a36Sopenharmony_ci		return;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	if (!fb->modifier) {
75262306a36Sopenharmony_ci		malidp_hw_write(mp->hwdev, 0, mp->layer->afbc_decoder_offset);
75362306a36Sopenharmony_ci		return;
75462306a36Sopenharmony_ci	}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	/* convert src values from Q16 fixed point to integer */
75762306a36Sopenharmony_ci	src_w = plane->state->src_w >> 16;
75862306a36Sopenharmony_ci	src_h = plane->state->src_h >> 16;
75962306a36Sopenharmony_ci	src_x = plane->state->src_x >> 16;
76062306a36Sopenharmony_ci	src_y = plane->state->src_y >> 16;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	val = ((fb->width - (src_x + src_w)) << MALIDP_AD_CROP_RIGHT_OFFSET) |
76362306a36Sopenharmony_ci		   src_x;
76462306a36Sopenharmony_ci	malidp_hw_write(mp->hwdev, val,
76562306a36Sopenharmony_ci			mp->layer->afbc_decoder_offset + MALIDP_AD_CROP_H);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	val = ((fb->height - (src_y + src_h)) << MALIDP_AD_CROP_BOTTOM_OFFSET) |
76862306a36Sopenharmony_ci		   src_y;
76962306a36Sopenharmony_ci	malidp_hw_write(mp->hwdev, val,
77062306a36Sopenharmony_ci			mp->layer->afbc_decoder_offset + MALIDP_AD_CROP_V);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	val = MALIDP_AD_EN;
77362306a36Sopenharmony_ci	if (fb->modifier & AFBC_FORMAT_MOD_SPLIT)
77462306a36Sopenharmony_ci		val |= MALIDP_AD_BS;
77562306a36Sopenharmony_ci	if (fb->modifier & AFBC_FORMAT_MOD_YTR)
77662306a36Sopenharmony_ci		val |= MALIDP_AD_YTR;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	malidp_hw_write(mp->hwdev, val, mp->layer->afbc_decoder_offset);
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic void malidp_de_plane_update(struct drm_plane *plane,
78262306a36Sopenharmony_ci				   struct drm_atomic_state *state)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
78562306a36Sopenharmony_ci									   plane);
78662306a36Sopenharmony_ci	struct malidp_plane *mp;
78762306a36Sopenharmony_ci	struct malidp_plane_state *ms = to_malidp_plane_state(plane->state);
78862306a36Sopenharmony_ci	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
78962306a36Sopenharmony_ci									   plane);
79062306a36Sopenharmony_ci	u16 pixel_alpha = new_state->pixel_blend_mode;
79162306a36Sopenharmony_ci	u8 plane_alpha = new_state->alpha >> 8;
79262306a36Sopenharmony_ci	u32 src_w, src_h, dest_w, dest_h, val;
79362306a36Sopenharmony_ci	int i;
79462306a36Sopenharmony_ci	struct drm_framebuffer *fb = plane->state->fb;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	mp = to_malidp_plane(plane);
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	/*
79962306a36Sopenharmony_ci	 * For AFBC framebuffer, use the framebuffer width and height for
80062306a36Sopenharmony_ci	 * configuring layer input size register.
80162306a36Sopenharmony_ci	 */
80262306a36Sopenharmony_ci	if (fb->modifier) {
80362306a36Sopenharmony_ci		src_w = fb->width;
80462306a36Sopenharmony_ci		src_h = fb->height;
80562306a36Sopenharmony_ci	} else {
80662306a36Sopenharmony_ci		/* convert src values from Q16 fixed point to integer */
80762306a36Sopenharmony_ci		src_w = new_state->src_w >> 16;
80862306a36Sopenharmony_ci		src_h = new_state->src_h >> 16;
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	dest_w = new_state->crtc_w;
81262306a36Sopenharmony_ci	dest_h = new_state->crtc_h;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	val = malidp_hw_read(mp->hwdev, mp->layer->base);
81562306a36Sopenharmony_ci	val = (val & ~LAYER_FORMAT_MASK) | ms->format;
81662306a36Sopenharmony_ci	malidp_hw_write(mp->hwdev, val, mp->layer->base);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	for (i = 0; i < ms->n_planes; i++)
81962306a36Sopenharmony_ci		malidp_set_plane_base_addr(fb, mp, i);
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	malidp_de_set_mmu_control(mp, ms);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	malidp_de_set_plane_pitches(mp, ms->n_planes,
82462306a36Sopenharmony_ci				    new_state->fb->pitches);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	if ((plane->state->color_encoding != old_state->color_encoding) ||
82762306a36Sopenharmony_ci	    (plane->state->color_range != old_state->color_range))
82862306a36Sopenharmony_ci		malidp_de_set_color_encoding(mp, plane->state->color_encoding,
82962306a36Sopenharmony_ci					     plane->state->color_range);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	malidp_hw_write(mp->hwdev, LAYER_H_VAL(src_w) | LAYER_V_VAL(src_h),
83262306a36Sopenharmony_ci			mp->layer->base + MALIDP_LAYER_SIZE);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	malidp_hw_write(mp->hwdev, LAYER_H_VAL(dest_w) | LAYER_V_VAL(dest_h),
83562306a36Sopenharmony_ci			mp->layer->base + MALIDP_LAYER_COMP_SIZE);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	malidp_hw_write(mp->hwdev, LAYER_H_VAL(new_state->crtc_x) |
83862306a36Sopenharmony_ci			LAYER_V_VAL(new_state->crtc_y),
83962306a36Sopenharmony_ci			mp->layer->base + MALIDP_LAYER_OFFSET);
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	if (mp->layer->id == DE_SMART) {
84262306a36Sopenharmony_ci		/*
84362306a36Sopenharmony_ci		 * Enable the first rectangle in the SMART layer to be
84462306a36Sopenharmony_ci		 * able to use it as a drm plane.
84562306a36Sopenharmony_ci		 */
84662306a36Sopenharmony_ci		malidp_hw_write(mp->hwdev, 1,
84762306a36Sopenharmony_ci				mp->layer->base + MALIDP550_LS_ENABLE);
84862306a36Sopenharmony_ci		malidp_hw_write(mp->hwdev,
84962306a36Sopenharmony_ci				LAYER_H_VAL(src_w) | LAYER_V_VAL(src_h),
85062306a36Sopenharmony_ci				mp->layer->base + MALIDP550_LS_R1_IN_SIZE);
85162306a36Sopenharmony_ci	}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	malidp_de_set_plane_afbc(plane);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	/* first clear the rotation bits */
85662306a36Sopenharmony_ci	val = malidp_hw_read(mp->hwdev, mp->layer->base + MALIDP_LAYER_CONTROL);
85762306a36Sopenharmony_ci	val &= ~LAYER_ROT_MASK;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	/* setup the rotation and axis flip bits */
86062306a36Sopenharmony_ci	if (new_state->rotation & DRM_MODE_ROTATE_MASK)
86162306a36Sopenharmony_ci		val |= ilog2(plane->state->rotation & DRM_MODE_ROTATE_MASK) <<
86262306a36Sopenharmony_ci		       LAYER_ROT_OFFSET;
86362306a36Sopenharmony_ci	if (new_state->rotation & DRM_MODE_REFLECT_X)
86462306a36Sopenharmony_ci		val |= LAYER_H_FLIP;
86562306a36Sopenharmony_ci	if (new_state->rotation & DRM_MODE_REFLECT_Y)
86662306a36Sopenharmony_ci		val |= LAYER_V_FLIP;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	val &= ~(LAYER_COMP_MASK | LAYER_PMUL_ENABLE | LAYER_ALPHA(0xff));
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	if (new_state->alpha != DRM_BLEND_ALPHA_OPAQUE) {
87162306a36Sopenharmony_ci		val |= LAYER_COMP_PLANE;
87262306a36Sopenharmony_ci	} else if (new_state->fb->format->has_alpha) {
87362306a36Sopenharmony_ci		/* We only care about blend mode if the format has alpha */
87462306a36Sopenharmony_ci		switch (pixel_alpha) {
87562306a36Sopenharmony_ci		case DRM_MODE_BLEND_PREMULTI:
87662306a36Sopenharmony_ci			val |= LAYER_COMP_PIXEL | LAYER_PMUL_ENABLE;
87762306a36Sopenharmony_ci			break;
87862306a36Sopenharmony_ci		case DRM_MODE_BLEND_COVERAGE:
87962306a36Sopenharmony_ci			val |= LAYER_COMP_PIXEL;
88062306a36Sopenharmony_ci			break;
88162306a36Sopenharmony_ci		}
88262306a36Sopenharmony_ci	}
88362306a36Sopenharmony_ci	val |= LAYER_ALPHA(plane_alpha);
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	val &= ~LAYER_FLOWCFG(LAYER_FLOWCFG_MASK);
88662306a36Sopenharmony_ci	if (new_state->crtc) {
88762306a36Sopenharmony_ci		struct malidp_crtc_state *m =
88862306a36Sopenharmony_ci			to_malidp_crtc_state(new_state->crtc->state);
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci		if (m->scaler_config.scale_enable &&
89162306a36Sopenharmony_ci		    m->scaler_config.plane_src_id == mp->layer->id)
89262306a36Sopenharmony_ci			val |= LAYER_FLOWCFG(LAYER_FLOWCFG_SCALE_SE);
89362306a36Sopenharmony_ci	}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	/* set the 'enable layer' bit */
89662306a36Sopenharmony_ci	val |= LAYER_ENABLE;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	malidp_hw_write(mp->hwdev, val,
89962306a36Sopenharmony_ci			mp->layer->base + MALIDP_LAYER_CONTROL);
90062306a36Sopenharmony_ci}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_cistatic void malidp_de_plane_disable(struct drm_plane *plane,
90362306a36Sopenharmony_ci				    struct drm_atomic_state *state)
90462306a36Sopenharmony_ci{
90562306a36Sopenharmony_ci	struct malidp_plane *mp = to_malidp_plane(plane);
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	malidp_hw_clearbits(mp->hwdev,
90862306a36Sopenharmony_ci			    LAYER_ENABLE | LAYER_FLOWCFG(LAYER_FLOWCFG_MASK),
90962306a36Sopenharmony_ci			    mp->layer->base + MALIDP_LAYER_CONTROL);
91062306a36Sopenharmony_ci}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_cistatic const struct drm_plane_helper_funcs malidp_de_plane_helper_funcs = {
91362306a36Sopenharmony_ci	.atomic_check = malidp_de_plane_check,
91462306a36Sopenharmony_ci	.atomic_update = malidp_de_plane_update,
91562306a36Sopenharmony_ci	.atomic_disable = malidp_de_plane_disable,
91662306a36Sopenharmony_ci};
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_cistatic const uint64_t linear_only_modifiers[] = {
91962306a36Sopenharmony_ci	DRM_FORMAT_MOD_LINEAR,
92062306a36Sopenharmony_ci	DRM_FORMAT_MOD_INVALID
92162306a36Sopenharmony_ci};
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ciint malidp_de_planes_init(struct drm_device *drm)
92462306a36Sopenharmony_ci{
92562306a36Sopenharmony_ci	struct malidp_drm *malidp = drm_to_malidp(drm);
92662306a36Sopenharmony_ci	const struct malidp_hw_regmap *map = &malidp->dev->hw->map;
92762306a36Sopenharmony_ci	struct malidp_plane *plane = NULL;
92862306a36Sopenharmony_ci	enum drm_plane_type plane_type;
92962306a36Sopenharmony_ci	unsigned long crtcs = BIT(drm->mode_config.num_crtc);
93062306a36Sopenharmony_ci	unsigned long flags = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_180 |
93162306a36Sopenharmony_ci			      DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y;
93262306a36Sopenharmony_ci	unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
93362306a36Sopenharmony_ci				  BIT(DRM_MODE_BLEND_PREMULTI)   |
93462306a36Sopenharmony_ci				  BIT(DRM_MODE_BLEND_COVERAGE);
93562306a36Sopenharmony_ci	u32 *formats;
93662306a36Sopenharmony_ci	int ret, i = 0, j = 0, n;
93762306a36Sopenharmony_ci	u64 supported_modifiers[MODIFIERS_COUNT_MAX];
93862306a36Sopenharmony_ci	const u64 *modifiers;
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	modifiers = malidp_format_modifiers;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	if (!(map->features & MALIDP_DEVICE_AFBC_SUPPORT_SPLIT)) {
94362306a36Sopenharmony_ci		/*
94462306a36Sopenharmony_ci		 * Since our hardware does not support SPLIT, so build the list
94562306a36Sopenharmony_ci		 * of supported modifiers excluding SPLIT ones.
94662306a36Sopenharmony_ci		 */
94762306a36Sopenharmony_ci		while (*modifiers != DRM_FORMAT_MOD_INVALID) {
94862306a36Sopenharmony_ci			if (!(*modifiers & AFBC_SPLIT))
94962306a36Sopenharmony_ci				supported_modifiers[j++] = *modifiers;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci			modifiers++;
95262306a36Sopenharmony_ci		}
95362306a36Sopenharmony_ci		supported_modifiers[j++] = DRM_FORMAT_MOD_INVALID;
95462306a36Sopenharmony_ci		modifiers = supported_modifiers;
95562306a36Sopenharmony_ci	}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	formats = kcalloc(map->n_pixel_formats, sizeof(*formats), GFP_KERNEL);
95862306a36Sopenharmony_ci	if (!formats) {
95962306a36Sopenharmony_ci		ret = -ENOMEM;
96062306a36Sopenharmony_ci		goto cleanup;
96162306a36Sopenharmony_ci	}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	for (i = 0; i < map->n_layers; i++) {
96462306a36Sopenharmony_ci		u8 id = map->layers[i].id;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci		/* build the list of DRM supported formats based on the map */
96762306a36Sopenharmony_ci		for (n = 0, j = 0;  j < map->n_pixel_formats; j++) {
96862306a36Sopenharmony_ci			if ((map->pixel_formats[j].layer & id) == id)
96962306a36Sopenharmony_ci				formats[n++] = map->pixel_formats[j].format;
97062306a36Sopenharmony_ci		}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci		plane_type = (i == 0) ? DRM_PLANE_TYPE_PRIMARY :
97362306a36Sopenharmony_ci					DRM_PLANE_TYPE_OVERLAY;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci		/*
97662306a36Sopenharmony_ci		 * All the layers except smart layer supports AFBC modifiers.
97762306a36Sopenharmony_ci		 */
97862306a36Sopenharmony_ci		plane = drmm_universal_plane_alloc(drm, struct malidp_plane, base,
97962306a36Sopenharmony_ci						   crtcs, &malidp_de_plane_funcs, formats, n,
98062306a36Sopenharmony_ci						   (id == DE_SMART) ? linear_only_modifiers :
98162306a36Sopenharmony_ci						   modifiers, plane_type, NULL);
98262306a36Sopenharmony_ci		if (IS_ERR(plane)) {
98362306a36Sopenharmony_ci			ret = PTR_ERR(plane);
98462306a36Sopenharmony_ci			goto cleanup;
98562306a36Sopenharmony_ci		}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci		drm_plane_helper_add(&plane->base,
98862306a36Sopenharmony_ci				     &malidp_de_plane_helper_funcs);
98962306a36Sopenharmony_ci		plane->hwdev = malidp->dev;
99062306a36Sopenharmony_ci		plane->layer = &map->layers[i];
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		drm_plane_create_alpha_property(&plane->base);
99362306a36Sopenharmony_ci		drm_plane_create_blend_mode_property(&plane->base, blend_caps);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci		if (id == DE_SMART) {
99662306a36Sopenharmony_ci			/* Skip the features which the SMART layer doesn't have. */
99762306a36Sopenharmony_ci			continue;
99862306a36Sopenharmony_ci		}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci		drm_plane_create_rotation_property(&plane->base, DRM_MODE_ROTATE_0, flags);
100162306a36Sopenharmony_ci		malidp_hw_write(malidp->dev, MALIDP_ALPHA_LUT,
100262306a36Sopenharmony_ci				plane->layer->base + MALIDP_LAYER_COMPOSE);
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci		/* Attach the YUV->RGB property only to video layers */
100562306a36Sopenharmony_ci		if (id & (DE_VIDEO1 | DE_VIDEO2)) {
100662306a36Sopenharmony_ci			/* default encoding for YUV->RGB is BT601 NARROW */
100762306a36Sopenharmony_ci			enum drm_color_encoding enc = DRM_COLOR_YCBCR_BT601;
100862306a36Sopenharmony_ci			enum drm_color_range range = DRM_COLOR_YCBCR_LIMITED_RANGE;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci			ret = drm_plane_create_color_properties(&plane->base,
101162306a36Sopenharmony_ci					BIT(DRM_COLOR_YCBCR_BT601) | \
101262306a36Sopenharmony_ci					BIT(DRM_COLOR_YCBCR_BT709) | \
101362306a36Sopenharmony_ci					BIT(DRM_COLOR_YCBCR_BT2020),
101462306a36Sopenharmony_ci					BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | \
101562306a36Sopenharmony_ci					BIT(DRM_COLOR_YCBCR_FULL_RANGE),
101662306a36Sopenharmony_ci					enc, range);
101762306a36Sopenharmony_ci			if (!ret)
101862306a36Sopenharmony_ci				/* program the HW registers */
101962306a36Sopenharmony_ci				malidp_de_set_color_encoding(plane, enc, range);
102062306a36Sopenharmony_ci			else
102162306a36Sopenharmony_ci				DRM_WARN("Failed to create video layer %d color properties\n", id);
102262306a36Sopenharmony_ci		}
102362306a36Sopenharmony_ci	}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	kfree(formats);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	return 0;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_cicleanup:
103062306a36Sopenharmony_ci	kfree(formats);
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	return ret;
103362306a36Sopenharmony_ci}
1034