xref: /openbmc/linux/drivers/gpu/drm/arm/malidp_planes.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
1e559355aSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ad49f860SLiviu Dudau /*
3ad49f860SLiviu Dudau  * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
4ad49f860SLiviu Dudau  * Author: Liviu Dudau <Liviu.Dudau@arm.com>
5ad49f860SLiviu Dudau  *
6ad49f860SLiviu Dudau  * ARM Mali DP plane manipulation routines.
7ad49f860SLiviu Dudau  */
8ad49f860SLiviu Dudau 
91f23a56aSJamie Fox #include <linux/iommu.h>
10535d1b94SSam Ravnborg #include <linux/platform_device.h>
111f23a56aSJamie Fox 
12b9c3315cSLiviu Dudau #include <drm/drm_atomic.h>
13ad49f860SLiviu Dudau #include <drm/drm_atomic_helper.h>
1490bb087fSVille Syrjälä #include <drm/drm_blend.h>
15535d1b94SSam Ravnborg #include <drm/drm_drv.h>
166bcfe8eaSDanilo Krummrich #include <drm/drm_fb_dma_helper.h>
17535d1b94SSam Ravnborg #include <drm/drm_fourcc.h>
18720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h>
194a83c26aSDanilo Krummrich #include <drm/drm_gem_dma_helper.h>
201f23a56aSJamie Fox #include <drm/drm_gem_framebuffer_helper.h>
2188d4d90fSMihail Atanassov #include <drm/drm_print.h>
22ad49f860SLiviu Dudau 
23ad49f860SLiviu Dudau #include "malidp_hw.h"
24ad49f860SLiviu Dudau #include "malidp_drv.h"
25ad49f860SLiviu Dudau 
26ad49f860SLiviu Dudau /* Layer specific register offsets */
27ad49f860SLiviu Dudau #define MALIDP_LAYER_FORMAT		0x000
28ad7fda2eSAyan Kumar Halder #define   LAYER_FORMAT_MASK		0x3f
29ad49f860SLiviu Dudau #define MALIDP_LAYER_CONTROL		0x004
30ad49f860SLiviu Dudau #define   LAYER_ENABLE			(1 << 0)
3128ce675bSMihail Atanassov #define   LAYER_FLOWCFG_MASK		7
3228ce675bSMihail Atanassov #define   LAYER_FLOWCFG(x)		(((x) & LAYER_FLOWCFG_MASK) << 1)
3328ce675bSMihail Atanassov #define     LAYER_FLOWCFG_SCALE_SE	3
34ad49f860SLiviu Dudau #define   LAYER_ROT_OFFSET		8
35ad49f860SLiviu Dudau #define   LAYER_H_FLIP			(1 << 10)
36ad49f860SLiviu Dudau #define   LAYER_V_FLIP			(1 << 11)
37ad49f860SLiviu Dudau #define   LAYER_ROT_MASK		(0xf << 8)
38c57eb710SBrian Starkey #define   LAYER_COMP_MASK		(0x3 << 12)
39c57eb710SBrian Starkey #define   LAYER_COMP_PIXEL		(0x3 << 12)
40c57eb710SBrian Starkey #define   LAYER_COMP_PLANE		(0x2 << 12)
41187f7f21SLowry Li #define   LAYER_PMUL_ENABLE		(0x1 << 14)
42f0437819SAyan Halder #define   LAYER_ALPHA_OFFSET		(16)
43f0437819SAyan Halder #define   LAYER_ALPHA_MASK		(0xff)
44f0437819SAyan Halder #define   LAYER_ALPHA(x)		(((x) & LAYER_ALPHA_MASK) << LAYER_ALPHA_OFFSET)
45c57eb710SBrian Starkey #define MALIDP_LAYER_COMPOSE		0x008
46ad49f860SLiviu Dudau #define MALIDP_LAYER_SIZE		0x00c
47ad49f860SLiviu Dudau #define   LAYER_H_VAL(x)		(((x) & 0x1fff) << 0)
48ad49f860SLiviu Dudau #define   LAYER_V_VAL(x)		(((x) & 0x1fff) << 16)
49ad49f860SLiviu Dudau #define MALIDP_LAYER_COMP_SIZE		0x010
50ad49f860SLiviu Dudau #define MALIDP_LAYER_OFFSET		0x014
51d1479f61SMihail Atanassov #define MALIDP550_LS_ENABLE		0x01c
52d1479f61SMihail Atanassov #define MALIDP550_LS_R1_IN_SIZE		0x020
53ad49f860SLiviu Dudau 
545e290226SAyan Kumar Halder #define MODIFIERS_COUNT_MAX		15
555e290226SAyan Kumar Halder 
56c57eb710SBrian Starkey /*
57c57eb710SBrian Starkey  * This 4-entry look-up-table is used to determine the full 8-bit alpha value
58c57eb710SBrian Starkey  * for formats with 1- or 2-bit alpha channels.
59c57eb710SBrian Starkey  * We set it to give 100%/0% opacity for 1-bit formats and 100%/66%/33%/0%
60c57eb710SBrian Starkey  * opacity for 2-bit formats.
61c57eb710SBrian Starkey  */
62c57eb710SBrian Starkey #define MALIDP_ALPHA_LUT 0xffaa5500
63c57eb710SBrian Starkey 
641f23a56aSJamie Fox /* page sizes the MMU prefetcher can support */
651f23a56aSJamie Fox #define MALIDP_MMU_PREFETCH_PARTIAL_PGSIZES	(SZ_4K | SZ_64K)
661f23a56aSJamie Fox #define MALIDP_MMU_PREFETCH_FULL_PGSIZES	(SZ_1M | SZ_2M)
671f23a56aSJamie Fox 
681f23a56aSJamie Fox /* readahead for partial-frame prefetch */
691f23a56aSJamie Fox #define MALIDP_MMU_PREFETCH_READAHEAD		8
701f23a56aSJamie Fox 
71fe10cd67SMihail Atanassov /*
72fe10cd67SMihail Atanassov  * Replicate what the default ->reset hook does: free the state pointer and
73fe10cd67SMihail Atanassov  * allocate a new empty object. We just need enough space to store
74fe10cd67SMihail Atanassov  * a malidp_plane_state instead of a drm_plane_state.
75fe10cd67SMihail Atanassov  */
malidp_plane_reset(struct drm_plane * plane)76fe10cd67SMihail Atanassov static void malidp_plane_reset(struct drm_plane *plane)
77fe10cd67SMihail Atanassov {
78fe10cd67SMihail Atanassov 	struct malidp_plane_state *state = to_malidp_plane_state(plane->state);
79fe10cd67SMihail Atanassov 
80fe10cd67SMihail Atanassov 	if (state)
81fe10cd67SMihail Atanassov 		__drm_atomic_helper_plane_destroy_state(&state->base);
82fe10cd67SMihail Atanassov 	kfree(state);
83fe10cd67SMihail Atanassov 	plane->state = NULL;
84fe10cd67SMihail Atanassov 	state = kzalloc(sizeof(*state), GFP_KERNEL);
85ffcf4626SAlexandru Gheorghe 	if (state)
86ffcf4626SAlexandru Gheorghe 		__drm_atomic_helper_plane_reset(plane, &state->base);
87fe10cd67SMihail Atanassov }
88fe10cd67SMihail Atanassov 
89ed8b0c0fSBaoyou Xie static struct
malidp_duplicate_plane_state(struct drm_plane * plane)90ed8b0c0fSBaoyou Xie drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane)
91ad49f860SLiviu Dudau {
92ad49f860SLiviu Dudau 	struct malidp_plane_state *state, *m_state;
93ad49f860SLiviu Dudau 
94ad49f860SLiviu Dudau 	if (!plane->state)
95ad49f860SLiviu Dudau 		return NULL;
96ad49f860SLiviu Dudau 
97ad49f860SLiviu Dudau 	state = kmalloc(sizeof(*state), GFP_KERNEL);
9894d8b9b7SShailendra Verma 	if (!state)
9994d8b9b7SShailendra Verma 		return NULL;
10094d8b9b7SShailendra Verma 
101ad49f860SLiviu Dudau 	m_state = to_malidp_plane_state(plane->state);
102ad49f860SLiviu Dudau 	__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
103ad49f860SLiviu Dudau 	state->rotmem_size = m_state->rotmem_size;
10470c94a3cSBrian Starkey 	state->format = m_state->format;
10570c94a3cSBrian Starkey 	state->n_planes = m_state->n_planes;
106ad49f860SLiviu Dudau 
1071f23a56aSJamie Fox 	state->mmu_prefetch_mode = m_state->mmu_prefetch_mode;
1081f23a56aSJamie Fox 	state->mmu_prefetch_pgsize = m_state->mmu_prefetch_pgsize;
1091f23a56aSJamie Fox 
110ad49f860SLiviu Dudau 	return &state->base;
111ad49f860SLiviu Dudau }
112ad49f860SLiviu Dudau 
malidp_destroy_plane_state(struct drm_plane * plane,struct drm_plane_state * state)113ed8b0c0fSBaoyou Xie static void malidp_destroy_plane_state(struct drm_plane *plane,
114ad49f860SLiviu Dudau 				       struct drm_plane_state *state)
115ad49f860SLiviu Dudau {
116ad49f860SLiviu Dudau 	struct malidp_plane_state *m_state = to_malidp_plane_state(state);
117ad49f860SLiviu Dudau 
118ad49f860SLiviu Dudau 	__drm_atomic_helper_plane_destroy_state(state);
119ad49f860SLiviu Dudau 	kfree(m_state);
120ad49f860SLiviu Dudau }
121ad49f860SLiviu Dudau 
1221f23a56aSJamie Fox static const char * const prefetch_mode_names[] = {
1231f23a56aSJamie Fox 	[MALIDP_PREFETCH_MODE_NONE] = "MMU_PREFETCH_NONE",
1241f23a56aSJamie Fox 	[MALIDP_PREFETCH_MODE_PARTIAL] = "MMU_PREFETCH_PARTIAL",
1251f23a56aSJamie Fox 	[MALIDP_PREFETCH_MODE_FULL] = "MMU_PREFETCH_FULL",
1261f23a56aSJamie Fox };
1271f23a56aSJamie Fox 
malidp_plane_atomic_print_state(struct drm_printer * p,const struct drm_plane_state * state)12888d4d90fSMihail Atanassov static void malidp_plane_atomic_print_state(struct drm_printer *p,
12988d4d90fSMihail Atanassov 					    const struct drm_plane_state *state)
13088d4d90fSMihail Atanassov {
13188d4d90fSMihail Atanassov 	struct malidp_plane_state *ms = to_malidp_plane_state(state);
13288d4d90fSMihail Atanassov 
13388d4d90fSMihail Atanassov 	drm_printf(p, "\trotmem_size=%u\n", ms->rotmem_size);
13488d4d90fSMihail Atanassov 	drm_printf(p, "\tformat_id=%u\n", ms->format);
13588d4d90fSMihail Atanassov 	drm_printf(p, "\tn_planes=%u\n", ms->n_planes);
1361f23a56aSJamie Fox 	drm_printf(p, "\tmmu_prefetch_mode=%s\n",
1371f23a56aSJamie Fox 		   prefetch_mode_names[ms->mmu_prefetch_mode]);
1381f23a56aSJamie Fox 	drm_printf(p, "\tmmu_prefetch_pgsize=%d\n", ms->mmu_prefetch_pgsize);
13988d4d90fSMihail Atanassov }
14088d4d90fSMihail Atanassov 
malidp_format_mod_supported(struct drm_device * drm,u32 format,u64 modifier)1415e290226SAyan Kumar Halder bool malidp_format_mod_supported(struct drm_device *drm,
1425e290226SAyan Kumar Halder 				 u32 format, u64 modifier)
1435e290226SAyan Kumar Halder {
1445e290226SAyan Kumar Halder 	const struct drm_format_info *info;
1455e290226SAyan Kumar Halder 	const u64 *modifiers;
1461b93d3cbSDanilo Krummrich 	struct malidp_drm *malidp = drm_to_malidp(drm);
1475e290226SAyan Kumar Halder 	const struct malidp_hw_regmap *map = &malidp->dev->hw->map;
1485e290226SAyan Kumar Halder 
1495e290226SAyan Kumar Halder 	if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID))
1505e290226SAyan Kumar Halder 		return false;
1515e290226SAyan Kumar Halder 
1525e290226SAyan Kumar Halder 	/* Some pixel formats are supported without any modifier */
1535e290226SAyan Kumar Halder 	if (modifier == DRM_FORMAT_MOD_LINEAR) {
1545e290226SAyan Kumar Halder 		/*
1555e290226SAyan Kumar Halder 		 * However these pixel formats need to be supported with
1565e290226SAyan Kumar Halder 		 * modifiers only
1575e290226SAyan Kumar Halder 		 */
1585e290226SAyan Kumar Halder 		return !malidp_hw_format_is_afbc_only(format);
1595e290226SAyan Kumar Halder 	}
1605e290226SAyan Kumar Halder 
16182ade934SThierry Reding 	if (!fourcc_mod_is_vendor(modifier, ARM)) {
1625e290226SAyan Kumar Halder 		DRM_ERROR("Unknown modifier (not Arm)\n");
1635e290226SAyan Kumar Halder 		return false;
1645e290226SAyan Kumar Halder 	}
1655e290226SAyan Kumar Halder 
1665e290226SAyan Kumar Halder 	if (modifier &
1675e290226SAyan Kumar Halder 	    ~DRM_FORMAT_MOD_ARM_AFBC(AFBC_MOD_VALID_BITS)) {
1685e290226SAyan Kumar Halder 		DRM_DEBUG_KMS("Unsupported modifiers\n");
1695e290226SAyan Kumar Halder 		return false;
1705e290226SAyan Kumar Halder 	}
1715e290226SAyan Kumar Halder 
1725e290226SAyan Kumar Halder 	modifiers = malidp_format_modifiers;
1735e290226SAyan Kumar Halder 
1745e290226SAyan Kumar Halder 	/* SPLIT buffers must use SPARSE layout */
1755e290226SAyan Kumar Halder 	if (WARN_ON_ONCE((modifier & AFBC_SPLIT) && !(modifier & AFBC_SPARSE)))
1765e290226SAyan Kumar Halder 		return false;
1775e290226SAyan Kumar Halder 
1785e290226SAyan Kumar Halder 	/* CBR only applies to YUV formats, where YTR should be always 0 */
1795e290226SAyan Kumar Halder 	if (WARN_ON_ONCE((modifier & AFBC_CBR) && (modifier & AFBC_YTR)))
1805e290226SAyan Kumar Halder 		return false;
1815e290226SAyan Kumar Halder 
1825e290226SAyan Kumar Halder 	while (*modifiers != DRM_FORMAT_MOD_INVALID) {
1835e290226SAyan Kumar Halder 		if (*modifiers == modifier)
1845e290226SAyan Kumar Halder 			break;
1855e290226SAyan Kumar Halder 
1865e290226SAyan Kumar Halder 		modifiers++;
1875e290226SAyan Kumar Halder 	}
1885e290226SAyan Kumar Halder 
1895e290226SAyan Kumar Halder 	/* return false, if the modifier was not found */
1905e290226SAyan Kumar Halder 	if (*modifiers == DRM_FORMAT_MOD_INVALID) {
1915e290226SAyan Kumar Halder 		DRM_DEBUG_KMS("Unsupported modifier\n");
1925e290226SAyan Kumar Halder 		return false;
1935e290226SAyan Kumar Halder 	}
1945e290226SAyan Kumar Halder 
1955e290226SAyan Kumar Halder 	info = drm_format_info(format);
1965e290226SAyan Kumar Halder 
1975e290226SAyan Kumar Halder 	if (info->num_planes != 1) {
1985e290226SAyan Kumar Halder 		DRM_DEBUG_KMS("AFBC buffers expect one plane\n");
1995e290226SAyan Kumar Halder 		return false;
2005e290226SAyan Kumar Halder 	}
2015e290226SAyan Kumar Halder 
2025e290226SAyan Kumar Halder 	if (malidp_hw_format_is_linear_only(format) == true) {
2035e290226SAyan Kumar Halder 		DRM_DEBUG_KMS("Given format (0x%x) is supported is linear mode only\n",
2045e290226SAyan Kumar Halder 			      format);
2055e290226SAyan Kumar Halder 		return false;
2065e290226SAyan Kumar Halder 	}
2075e290226SAyan Kumar Halder 
2085e290226SAyan Kumar Halder 	/*
2095e290226SAyan Kumar Halder 	 * RGB formats need to provide YTR modifier and YUV formats should not
2105e290226SAyan Kumar Halder 	 * provide YTR modifier.
2115e290226SAyan Kumar Halder 	 */
2125e290226SAyan Kumar Halder 	if (!(info->is_yuv) != !!(modifier & AFBC_FORMAT_MOD_YTR)) {
2135e290226SAyan Kumar Halder 		DRM_DEBUG_KMS("AFBC_FORMAT_MOD_YTR is %s for %s formats\n",
2145e290226SAyan Kumar Halder 			      info->is_yuv ? "disallowed" : "mandatory",
2155e290226SAyan Kumar Halder 			      info->is_yuv ? "YUV" : "RGB");
2165e290226SAyan Kumar Halder 		return false;
2175e290226SAyan Kumar Halder 	}
2185e290226SAyan Kumar Halder 
2195e290226SAyan Kumar Halder 	if (modifier & AFBC_SPLIT) {
2205e290226SAyan Kumar Halder 		if (!info->is_yuv) {
221b0f986b4SMaxime Ripard 			if (info->cpp[0] <= 2) {
2225e290226SAyan Kumar Halder 				DRM_DEBUG_KMS("RGB formats <= 16bpp are not supported with SPLIT\n");
2235e290226SAyan Kumar Halder 				return false;
2245e290226SAyan Kumar Halder 			}
2255e290226SAyan Kumar Halder 		}
2265e290226SAyan Kumar Halder 
227f3e9632cSMaxime Ripard 		if ((info->hsub != 1) || (info->vsub != 1)) {
2285e290226SAyan Kumar Halder 			if (!(format == DRM_FORMAT_YUV420_10BIT &&
2295e290226SAyan Kumar Halder 			      (map->features & MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT))) {
2305e290226SAyan Kumar Halder 				DRM_DEBUG_KMS("Formats which are sub-sampled should never be split\n");
2315e290226SAyan Kumar Halder 				return false;
2325e290226SAyan Kumar Halder 			}
2335e290226SAyan Kumar Halder 		}
2345e290226SAyan Kumar Halder 	}
2355e290226SAyan Kumar Halder 
2365e290226SAyan Kumar Halder 	if (modifier & AFBC_CBR) {
237f3e9632cSMaxime Ripard 		if ((info->hsub == 1) || (info->vsub == 1)) {
2385e290226SAyan Kumar Halder 			DRM_DEBUG_KMS("Formats which are not sub-sampled should not have CBR set\n");
2395e290226SAyan Kumar Halder 			return false;
2405e290226SAyan Kumar Halder 		}
2415e290226SAyan Kumar Halder 	}
2425e290226SAyan Kumar Halder 
2435e290226SAyan Kumar Halder 	return true;
2445e290226SAyan Kumar Halder }
2455e290226SAyan Kumar Halder 
malidp_format_mod_supported_per_plane(struct drm_plane * plane,u32 format,u64 modifier)2465e290226SAyan Kumar Halder static bool malidp_format_mod_supported_per_plane(struct drm_plane *plane,
2475e290226SAyan Kumar Halder 						  u32 format, u64 modifier)
2485e290226SAyan Kumar Halder {
2495e290226SAyan Kumar Halder 	return malidp_format_mod_supported(plane->dev, format, modifier);
2505e290226SAyan Kumar Halder }
2515e290226SAyan Kumar Halder 
252ad49f860SLiviu Dudau static const struct drm_plane_funcs malidp_de_plane_funcs = {
253ad49f860SLiviu Dudau 	.update_plane = drm_atomic_helper_update_plane,
254ad49f860SLiviu Dudau 	.disable_plane = drm_atomic_helper_disable_plane,
255fe10cd67SMihail Atanassov 	.reset = malidp_plane_reset,
256ad49f860SLiviu Dudau 	.atomic_duplicate_state = malidp_duplicate_plane_state,
257ad49f860SLiviu Dudau 	.atomic_destroy_state = malidp_destroy_plane_state,
25888d4d90fSMihail Atanassov 	.atomic_print_state = malidp_plane_atomic_print_state,
2595e290226SAyan Kumar Halder 	.format_mod_supported = malidp_format_mod_supported_per_plane,
260ad49f860SLiviu Dudau };
261ad49f860SLiviu Dudau 
malidp_se_check_scaling(struct malidp_plane * mp,struct drm_plane_state * state)26228ce675bSMihail Atanassov static int malidp_se_check_scaling(struct malidp_plane *mp,
26328ce675bSMihail Atanassov 				   struct drm_plane_state *state)
26428ce675bSMihail Atanassov {
26528ce675bSMihail Atanassov 	struct drm_crtc_state *crtc_state =
26628ce675bSMihail Atanassov 		drm_atomic_get_existing_crtc_state(state->state, state->crtc);
26728ce675bSMihail Atanassov 	struct malidp_crtc_state *mc;
26828ce675bSMihail Atanassov 	u32 src_w, src_h;
26928ce675bSMihail Atanassov 	int ret;
27028ce675bSMihail Atanassov 
27128ce675bSMihail Atanassov 	if (!crtc_state)
27228ce675bSMihail Atanassov 		return -EINVAL;
27328ce675bSMihail Atanassov 
274f2f2c85cSDan Carpenter 	mc = to_malidp_crtc_state(crtc_state);
275f2f2c85cSDan Carpenter 
27681af63a4SVille Syrjälä 	ret = drm_atomic_helper_check_plane_state(state, crtc_state,
27710b47ee0SVille Syrjälä 						  0, INT_MAX, true, true);
27828ce675bSMihail Atanassov 	if (ret)
27928ce675bSMihail Atanassov 		return ret;
28028ce675bSMihail Atanassov 
281e0521c05SLiviu Dudau 	if (state->rotation & MALIDP_ROTATED_MASK) {
282e0521c05SLiviu Dudau 		src_w = state->src_h >> 16;
283e0521c05SLiviu Dudau 		src_h = state->src_w >> 16;
284e0521c05SLiviu Dudau 	} else {
28528ce675bSMihail Atanassov 		src_w = state->src_w >> 16;
28628ce675bSMihail Atanassov 		src_h = state->src_h >> 16;
287e0521c05SLiviu Dudau 	}
288e0521c05SLiviu Dudau 
28928ce675bSMihail Atanassov 	if ((state->crtc_w == src_w) && (state->crtc_h == src_h)) {
29028ce675bSMihail Atanassov 		/* Scaling not necessary for this plane. */
29128ce675bSMihail Atanassov 		mc->scaled_planes_mask &= ~(mp->layer->id);
29228ce675bSMihail Atanassov 		return 0;
29328ce675bSMihail Atanassov 	}
29428ce675bSMihail Atanassov 
29528ce675bSMihail Atanassov 	if (mp->layer->id & (DE_SMART | DE_GRAPHICS2))
29628ce675bSMihail Atanassov 		return -EINVAL;
29728ce675bSMihail Atanassov 
29828ce675bSMihail Atanassov 	mc->scaled_planes_mask |= mp->layer->id;
29928ce675bSMihail Atanassov 	/* Defer scaling requirements calculation to the crtc check. */
30028ce675bSMihail Atanassov 	return 0;
30128ce675bSMihail Atanassov }
30228ce675bSMihail Atanassov 
malidp_get_pgsize_bitmap(struct malidp_plane * mp)3031f23a56aSJamie Fox static u32 malidp_get_pgsize_bitmap(struct malidp_plane *mp)
3041f23a56aSJamie Fox {
305b5c7d197SRobin Murphy 	struct iommu_domain *mmu_dom;
3061f23a56aSJamie Fox 
307b5c7d197SRobin Murphy 	mmu_dom = iommu_get_domain_for_dev(mp->base.dev->dev);
3081f23a56aSJamie Fox 	if (mmu_dom)
309b5c7d197SRobin Murphy 		return mmu_dom->pgsize_bitmap;
3101f23a56aSJamie Fox 
311b5c7d197SRobin Murphy 	return 0;
3121f23a56aSJamie Fox }
3131f23a56aSJamie Fox 
3141f23a56aSJamie Fox /*
3151f23a56aSJamie Fox  * Check if the framebuffer is entirely made up of pages at least pgsize in
3161f23a56aSJamie Fox  * size. Only a heuristic: assumes that each scatterlist entry has been aligned
3171f23a56aSJamie Fox  * to the largest page size smaller than its length and that the MMU maps to
3181f23a56aSJamie Fox  * the largest page size possible.
3191f23a56aSJamie Fox  */
malidp_check_pages_threshold(struct malidp_plane_state * ms,u32 pgsize)3201f23a56aSJamie Fox static bool malidp_check_pages_threshold(struct malidp_plane_state *ms,
3211f23a56aSJamie Fox 					 u32 pgsize)
3221f23a56aSJamie Fox {
3231f23a56aSJamie Fox 	int i;
3241f23a56aSJamie Fox 
3251f23a56aSJamie Fox 	for (i = 0; i < ms->n_planes; i++) {
3261f23a56aSJamie Fox 		struct drm_gem_object *obj;
3274a83c26aSDanilo Krummrich 		struct drm_gem_dma_object *dma_obj;
3281f23a56aSJamie Fox 		struct sg_table *sgt;
3291f23a56aSJamie Fox 		struct scatterlist *sgl;
3301f23a56aSJamie Fox 
3311f23a56aSJamie Fox 		obj = drm_gem_fb_get_obj(ms->base.fb, i);
3324a83c26aSDanilo Krummrich 		dma_obj = to_drm_gem_dma_obj(obj);
3331f23a56aSJamie Fox 
3344a83c26aSDanilo Krummrich 		if (dma_obj->sgt)
3354a83c26aSDanilo Krummrich 			sgt = dma_obj->sgt;
3361f23a56aSJamie Fox 		else
337d3d1bbe7SThomas Zimmermann 			sgt = obj->funcs->get_sg_table(obj);
3381f23a56aSJamie Fox 
33915342f93SMiaoqian Lin 		if (IS_ERR(sgt))
3401f23a56aSJamie Fox 			return false;
3411f23a56aSJamie Fox 
3421f23a56aSJamie Fox 		sgl = sgt->sgl;
3431f23a56aSJamie Fox 
3441f23a56aSJamie Fox 		while (sgl) {
3451f23a56aSJamie Fox 			if (sgl->length < pgsize) {
3464a83c26aSDanilo Krummrich 				if (!dma_obj->sgt)
3471f23a56aSJamie Fox 					kfree(sgt);
3481f23a56aSJamie Fox 				return false;
3491f23a56aSJamie Fox 			}
3501f23a56aSJamie Fox 
3511f23a56aSJamie Fox 			sgl = sg_next(sgl);
3521f23a56aSJamie Fox 		}
3534a83c26aSDanilo Krummrich 		if (!dma_obj->sgt)
3541f23a56aSJamie Fox 			kfree(sgt);
3551f23a56aSJamie Fox 	}
3561f23a56aSJamie Fox 
3571f23a56aSJamie Fox 	return true;
3581f23a56aSJamie Fox }
3591f23a56aSJamie Fox 
3601f23a56aSJamie Fox /*
3611f23a56aSJamie Fox  * Check if it is possible to enable partial-frame MMU prefetch given the
3621f23a56aSJamie Fox  * current format, AFBC state and rotation.
3631f23a56aSJamie Fox  */
malidp_partial_prefetch_supported(u32 format,u64 modifier,unsigned int rotation)3641f23a56aSJamie Fox static bool malidp_partial_prefetch_supported(u32 format, u64 modifier,
3651f23a56aSJamie Fox 					      unsigned int rotation)
3661f23a56aSJamie Fox {
3671f23a56aSJamie Fox 	bool afbc, sparse;
3681f23a56aSJamie Fox 
3691f23a56aSJamie Fox 	/* rotation and horizontal flip not supported for partial prefetch */
3701f23a56aSJamie Fox 	if (rotation & (DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_180 |
3711f23a56aSJamie Fox 			DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X))
3721f23a56aSJamie Fox 		return false;
3731f23a56aSJamie Fox 
3741f23a56aSJamie Fox 	afbc = modifier & DRM_FORMAT_MOD_ARM_AFBC(0);
3751f23a56aSJamie Fox 	sparse = modifier & AFBC_FORMAT_MOD_SPARSE;
3761f23a56aSJamie Fox 
3771f23a56aSJamie Fox 	switch (format) {
3781f23a56aSJamie Fox 	case DRM_FORMAT_ARGB2101010:
3791f23a56aSJamie Fox 	case DRM_FORMAT_RGBA1010102:
3801f23a56aSJamie Fox 	case DRM_FORMAT_BGRA1010102:
3811f23a56aSJamie Fox 	case DRM_FORMAT_ARGB8888:
3821f23a56aSJamie Fox 	case DRM_FORMAT_RGBA8888:
3831f23a56aSJamie Fox 	case DRM_FORMAT_BGRA8888:
3841f23a56aSJamie Fox 	case DRM_FORMAT_XRGB8888:
3851f23a56aSJamie Fox 	case DRM_FORMAT_XBGR8888:
3861f23a56aSJamie Fox 	case DRM_FORMAT_RGBX8888:
3871f23a56aSJamie Fox 	case DRM_FORMAT_BGRX8888:
3881f23a56aSJamie Fox 	case DRM_FORMAT_RGB888:
3891f23a56aSJamie Fox 	case DRM_FORMAT_RGBA5551:
3901f23a56aSJamie Fox 	case DRM_FORMAT_RGB565:
3911f23a56aSJamie Fox 		/* always supported */
3921f23a56aSJamie Fox 		return true;
3931f23a56aSJamie Fox 
3941f23a56aSJamie Fox 	case DRM_FORMAT_ABGR2101010:
3951f23a56aSJamie Fox 	case DRM_FORMAT_ABGR8888:
3961f23a56aSJamie Fox 	case DRM_FORMAT_ABGR1555:
3971f23a56aSJamie Fox 	case DRM_FORMAT_BGR565:
3981f23a56aSJamie Fox 		/* supported, but if AFBC then must be sparse mode */
3991f23a56aSJamie Fox 		return (!afbc) || (afbc && sparse);
4001f23a56aSJamie Fox 
4011f23a56aSJamie Fox 	case DRM_FORMAT_BGR888:
4021f23a56aSJamie Fox 		/* supported, but not for AFBC */
4031f23a56aSJamie Fox 		return !afbc;
4041f23a56aSJamie Fox 
4051f23a56aSJamie Fox 	case DRM_FORMAT_YUYV:
4061f23a56aSJamie Fox 	case DRM_FORMAT_UYVY:
4071f23a56aSJamie Fox 	case DRM_FORMAT_NV12:
4081f23a56aSJamie Fox 	case DRM_FORMAT_YUV420:
4091f23a56aSJamie Fox 		/* not supported */
4101f23a56aSJamie Fox 		return false;
4111f23a56aSJamie Fox 
4121f23a56aSJamie Fox 	default:
4131f23a56aSJamie Fox 		return false;
4141f23a56aSJamie Fox 	}
4151f23a56aSJamie Fox }
4161f23a56aSJamie Fox 
4171f23a56aSJamie Fox /*
4181f23a56aSJamie Fox  * Select the preferred MMU prefetch mode. Full-frame prefetch is preferred as
4191f23a56aSJamie Fox  * long as the framebuffer is all large pages. Otherwise partial-frame prefetch
4201f23a56aSJamie Fox  * is selected as long as it is supported for the current format. The selected
4211f23a56aSJamie Fox  * page size for prefetch is returned in pgsize_bitmap.
4221f23a56aSJamie Fox  */
malidp_mmu_prefetch_select_mode(struct malidp_plane_state * ms,u32 * pgsize_bitmap)4231f23a56aSJamie Fox static enum mmu_prefetch_mode malidp_mmu_prefetch_select_mode
4241f23a56aSJamie Fox 		(struct malidp_plane_state *ms,	u32 *pgsize_bitmap)
4251f23a56aSJamie Fox {
4261f23a56aSJamie Fox 	u32 pgsizes;
4271f23a56aSJamie Fox 
4281f23a56aSJamie Fox 	/* get the full-frame prefetch page size(s) supported by the MMU */
4291f23a56aSJamie Fox 	pgsizes = *pgsize_bitmap & MALIDP_MMU_PREFETCH_FULL_PGSIZES;
4301f23a56aSJamie Fox 
4311f23a56aSJamie Fox 	while (pgsizes) {
4321f23a56aSJamie Fox 		u32 largest_pgsize = 1 << __fls(pgsizes);
4331f23a56aSJamie Fox 
4341f23a56aSJamie Fox 		if (malidp_check_pages_threshold(ms, largest_pgsize)) {
4351f23a56aSJamie Fox 			*pgsize_bitmap = largest_pgsize;
4361f23a56aSJamie Fox 			return MALIDP_PREFETCH_MODE_FULL;
4371f23a56aSJamie Fox 		}
4381f23a56aSJamie Fox 
4391f23a56aSJamie Fox 		pgsizes -= largest_pgsize;
4401f23a56aSJamie Fox 	}
4411f23a56aSJamie Fox 
4421f23a56aSJamie Fox 	/* get the partial-frame prefetch page size(s) supported by the MMU */
4431f23a56aSJamie Fox 	pgsizes = *pgsize_bitmap & MALIDP_MMU_PREFETCH_PARTIAL_PGSIZES;
4441f23a56aSJamie Fox 
4451f23a56aSJamie Fox 	if (malidp_partial_prefetch_supported(ms->base.fb->format->format,
4461f23a56aSJamie Fox 					      ms->base.fb->modifier,
4471f23a56aSJamie Fox 					      ms->base.rotation)) {
4481f23a56aSJamie Fox 		/* partial prefetch using the smallest page size */
4491f23a56aSJamie Fox 		*pgsize_bitmap = 1 << __ffs(pgsizes);
4501f23a56aSJamie Fox 		return MALIDP_PREFETCH_MODE_PARTIAL;
4511f23a56aSJamie Fox 	}
4521f23a56aSJamie Fox 	*pgsize_bitmap = 0;
4531f23a56aSJamie Fox 	return MALIDP_PREFETCH_MODE_NONE;
4541f23a56aSJamie Fox }
4551f23a56aSJamie Fox 
malidp_calc_mmu_control_value(enum mmu_prefetch_mode mode,u8 readahead,u8 n_planes,u32 pgsize)4561f23a56aSJamie Fox static u32 malidp_calc_mmu_control_value(enum mmu_prefetch_mode mode,
4571f23a56aSJamie Fox 					 u8 readahead, u8 n_planes, u32 pgsize)
4581f23a56aSJamie Fox {
4591f23a56aSJamie Fox 	u32 mmu_ctrl = 0;
4601f23a56aSJamie Fox 
4611f23a56aSJamie Fox 	if (mode != MALIDP_PREFETCH_MODE_NONE) {
4621f23a56aSJamie Fox 		mmu_ctrl |= MALIDP_MMU_CTRL_EN;
4631f23a56aSJamie Fox 
4641f23a56aSJamie Fox 		if (mode == MALIDP_PREFETCH_MODE_PARTIAL) {
4651f23a56aSJamie Fox 			mmu_ctrl |= MALIDP_MMU_CTRL_MODE;
4661f23a56aSJamie Fox 			mmu_ctrl |= MALIDP_MMU_CTRL_PP_NUM_REQ(readahead);
4671f23a56aSJamie Fox 		}
4681f23a56aSJamie Fox 
4691f23a56aSJamie Fox 		if (pgsize == SZ_64K || pgsize == SZ_2M) {
4701f23a56aSJamie Fox 			int i;
4711f23a56aSJamie Fox 
4721f23a56aSJamie Fox 			for (i = 0; i < n_planes; i++)
4731f23a56aSJamie Fox 				mmu_ctrl |= MALIDP_MMU_CTRL_PX_PS(i);
4741f23a56aSJamie Fox 		}
4751f23a56aSJamie Fox 	}
4761f23a56aSJamie Fox 
4771f23a56aSJamie Fox 	return mmu_ctrl;
4781f23a56aSJamie Fox }
4791f23a56aSJamie Fox 
malidp_de_prefetch_settings(struct malidp_plane * mp,struct malidp_plane_state * ms)4801f23a56aSJamie Fox static void malidp_de_prefetch_settings(struct malidp_plane *mp,
4811f23a56aSJamie Fox 					struct malidp_plane_state *ms)
4821f23a56aSJamie Fox {
4831f23a56aSJamie Fox 	if (!mp->layer->mmu_ctrl_offset)
4841f23a56aSJamie Fox 		return;
4851f23a56aSJamie Fox 
4861f23a56aSJamie Fox 	/* get the page sizes supported by the MMU */
4871f23a56aSJamie Fox 	ms->mmu_prefetch_pgsize = malidp_get_pgsize_bitmap(mp);
4881f23a56aSJamie Fox 	ms->mmu_prefetch_mode  =
4891f23a56aSJamie Fox 		malidp_mmu_prefetch_select_mode(ms, &ms->mmu_prefetch_pgsize);
4901f23a56aSJamie Fox }
4911f23a56aSJamie Fox 
malidp_de_plane_check(struct drm_plane * plane,struct drm_atomic_state * state)492ad49f860SLiviu Dudau static int malidp_de_plane_check(struct drm_plane *plane,
4937c11b99aSMaxime Ripard 				 struct drm_atomic_state *state)
494ad49f860SLiviu Dudau {
4957c11b99aSMaxime Ripard 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
4967c11b99aSMaxime Ripard 										 plane);
497ad49f860SLiviu Dudau 	struct malidp_plane *mp = to_malidp_plane(plane);
498ba5c1649SMaxime Ripard 	struct malidp_plane_state *ms = to_malidp_plane_state(new_plane_state);
499ba5c1649SMaxime Ripard 	bool rotated = new_plane_state->rotation & MALIDP_ROTATED_MASK;
500a46a096aSBrian Starkey 	struct drm_framebuffer *fb;
501ba5c1649SMaxime Ripard 	u16 pixel_alpha = new_plane_state->pixel_blend_mode;
502b9c3315cSLiviu Dudau 	int i, ret;
50355bc277dSAlexandru Gheorghe 	unsigned int block_w, block_h;
504ad49f860SLiviu Dudau 
505ba5c1649SMaxime Ripard 	if (!new_plane_state->crtc || WARN_ON(!new_plane_state->fb))
506ad49f860SLiviu Dudau 		return 0;
507ad49f860SLiviu Dudau 
508ba5c1649SMaxime Ripard 	fb = new_plane_state->fb;
509a46a096aSBrian Starkey 
510a6993b21SLiviu Dudau 	ms->format = malidp_hw_get_format_id(&mp->hwdev->hw->map,
5115e290226SAyan Kumar Halder 					     mp->layer->id, fb->format->format,
5125e290226SAyan Kumar Halder 					     !!fb->modifier);
51370c94a3cSBrian Starkey 	if (ms->format == MALIDP_INVALID_FORMAT_ID)
514ad49f860SLiviu Dudau 		return -EINVAL;
515ad49f860SLiviu Dudau 
516bcb0b461SVille Syrjälä 	ms->n_planes = fb->format->num_planes;
51770c94a3cSBrian Starkey 	for (i = 0; i < ms->n_planes; i++) {
518fcad73b9SLiviu Dudau 		u8 alignment = malidp_hw_get_pitch_align(mp->hwdev, rotated);
51955bc277dSAlexandru Gheorghe 
5200f6c18deSAyan Kumar Halder 		if (((fb->pitches[i] * drm_format_info_block_height(fb->format, i))
5210f6c18deSAyan Kumar Halder 				& (alignment - 1)) && !(fb->modifier)) {
522a46a096aSBrian Starkey 			DRM_DEBUG_KMS("Invalid pitch %u for plane %d\n",
523a46a096aSBrian Starkey 				      fb->pitches[i], i);
524a46a096aSBrian Starkey 			return -EINVAL;
525a46a096aSBrian Starkey 		}
526a46a096aSBrian Starkey 	}
527a46a096aSBrian Starkey 
52855bc277dSAlexandru Gheorghe 	block_w = drm_format_info_block_width(fb->format, 0);
52955bc277dSAlexandru Gheorghe 	block_h = drm_format_info_block_height(fb->format, 0);
53055bc277dSAlexandru Gheorghe 	if (fb->width % block_w || fb->height % block_h) {
53155bc277dSAlexandru Gheorghe 		DRM_DEBUG_KMS("Buffer width/height needs to be a multiple of tile sizes");
53255bc277dSAlexandru Gheorghe 		return -EINVAL;
53355bc277dSAlexandru Gheorghe 	}
534ba5c1649SMaxime Ripard 	if ((new_plane_state->src_x >> 16) % block_w || (new_plane_state->src_y >> 16) % block_h) {
53555bc277dSAlexandru Gheorghe 		DRM_DEBUG_KMS("Plane src_x/src_y needs to be a multiple of tile sizes");
53655bc277dSAlexandru Gheorghe 		return -EINVAL;
53755bc277dSAlexandru Gheorghe 	}
53855bc277dSAlexandru Gheorghe 
539ba5c1649SMaxime Ripard 	if ((new_plane_state->crtc_w > mp->hwdev->max_line_size) ||
540ba5c1649SMaxime Ripard 	    (new_plane_state->crtc_h > mp->hwdev->max_line_size) ||
541ba5c1649SMaxime Ripard 	    (new_plane_state->crtc_w < mp->hwdev->min_line_size) ||
542ba5c1649SMaxime Ripard 	    (new_plane_state->crtc_h < mp->hwdev->min_line_size))
543ad49f860SLiviu Dudau 		return -EINVAL;
544ad49f860SLiviu Dudau 
54583d642eeSMihail Atanassov 	/*
54683d642eeSMihail Atanassov 	 * DP550/650 video layers can accept 3 plane formats only if
54783d642eeSMihail Atanassov 	 * fb->pitches[1] == fb->pitches[2] since they don't have a
54883d642eeSMihail Atanassov 	 * third plane stride register.
54983d642eeSMihail Atanassov 	 */
55083d642eeSMihail Atanassov 	if (ms->n_planes == 3 &&
551a6993b21SLiviu Dudau 	    !(mp->hwdev->hw->features & MALIDP_DEVICE_LV_HAS_3_STRIDES) &&
552ba5c1649SMaxime Ripard 	    (new_plane_state->fb->pitches[1] != new_plane_state->fb->pitches[2]))
55383d642eeSMihail Atanassov 		return -EINVAL;
55483d642eeSMihail Atanassov 
555ba5c1649SMaxime Ripard 	ret = malidp_se_check_scaling(mp, new_plane_state);
55628ce675bSMihail Atanassov 	if (ret)
55728ce675bSMihail Atanassov 		return ret;
55828ce675bSMihail Atanassov 
55966da13a5SLiviu Dudau 	/* validate the rotation constraints for each layer */
560ba5c1649SMaxime Ripard 	if (new_plane_state->rotation != DRM_MODE_ROTATE_0) {
56166da13a5SLiviu Dudau 		if (mp->layer->rot == ROTATE_NONE)
562ad49f860SLiviu Dudau 			return -EINVAL;
56366da13a5SLiviu Dudau 		if ((mp->layer->rot == ROTATE_COMPRESSED) && !(fb->modifier))
56466da13a5SLiviu Dudau 			return -EINVAL;
56566da13a5SLiviu Dudau 		/*
56666da13a5SLiviu Dudau 		 * packed RGB888 / BGR888 can't be rotated or flipped
56766da13a5SLiviu Dudau 		 * unless they are stored in a compressed way
56866da13a5SLiviu Dudau 		 */
56966da13a5SLiviu Dudau 		if ((fb->format->format == DRM_FORMAT_RGB888 ||
57066da13a5SLiviu Dudau 		     fb->format->format == DRM_FORMAT_BGR888) && !(fb->modifier))
57166da13a5SLiviu Dudau 			return -EINVAL;
57266da13a5SLiviu Dudau 	}
573ad49f860SLiviu Dudau 
5745e290226SAyan Kumar Halder 	/* SMART layer does not support AFBC */
5755e290226SAyan Kumar Halder 	if (mp->layer->id == DE_SMART && fb->modifier) {
5765e290226SAyan Kumar Halder 		DRM_ERROR("AFBC framebuffer not supported in SMART layer");
5775e290226SAyan Kumar Halder 		return -EINVAL;
5785e290226SAyan Kumar Halder 	}
5795e290226SAyan Kumar Halder 
580ad49f860SLiviu Dudau 	ms->rotmem_size = 0;
581ba5c1649SMaxime Ripard 	if (new_plane_state->rotation & MALIDP_ROTATED_MASK) {
582ad49f860SLiviu Dudau 		int val;
583ad49f860SLiviu Dudau 
584ba5c1649SMaxime Ripard 		val = mp->hwdev->hw->rotmem_required(mp->hwdev, new_plane_state->crtc_w,
585ba5c1649SMaxime Ripard 						     new_plane_state->crtc_h,
586b8207562SAyan Kumar Halder 						     fb->format->format,
587b8207562SAyan Kumar Halder 						     !!(fb->modifier));
588ad49f860SLiviu Dudau 		if (val < 0)
589ad49f860SLiviu Dudau 			return val;
590ad49f860SLiviu Dudau 
591ad49f860SLiviu Dudau 		ms->rotmem_size = val;
592ad49f860SLiviu Dudau 	}
593ad49f860SLiviu Dudau 
594187f7f21SLowry Li 	/* HW can't support plane + pixel blending */
595ba5c1649SMaxime Ripard 	if ((new_plane_state->alpha != DRM_BLEND_ALPHA_OPAQUE) &&
596187f7f21SLowry Li 	    (pixel_alpha != DRM_MODE_BLEND_PIXEL_NONE) &&
597187f7f21SLowry Li 	    fb->format->has_alpha)
598187f7f21SLowry Li 		return -EINVAL;
599187f7f21SLowry Li 
6001f23a56aSJamie Fox 	malidp_de_prefetch_settings(mp, ms);
6011f23a56aSJamie Fox 
602ad49f860SLiviu Dudau 	return 0;
603ad49f860SLiviu Dudau }
604ad49f860SLiviu Dudau 
malidp_de_set_plane_pitches(struct malidp_plane * mp,int num_planes,unsigned int pitches[3])60583d642eeSMihail Atanassov static void malidp_de_set_plane_pitches(struct malidp_plane *mp,
60683d642eeSMihail Atanassov 					int num_planes, unsigned int pitches[3])
60783d642eeSMihail Atanassov {
60883d642eeSMihail Atanassov 	int i;
60983d642eeSMihail Atanassov 	int num_strides = num_planes;
61083d642eeSMihail Atanassov 
61183d642eeSMihail Atanassov 	if (!mp->layer->stride_offset)
61283d642eeSMihail Atanassov 		return;
61383d642eeSMihail Atanassov 
61483d642eeSMihail Atanassov 	if (num_planes == 3)
615a6993b21SLiviu Dudau 		num_strides = (mp->hwdev->hw->features &
61683d642eeSMihail Atanassov 			       MALIDP_DEVICE_LV_HAS_3_STRIDES) ? 3 : 2;
61783d642eeSMihail Atanassov 
61855bc277dSAlexandru Gheorghe 	/*
61955bc277dSAlexandru Gheorghe 	 * The drm convention for pitch is that it needs to cover width * cpp,
62055bc277dSAlexandru Gheorghe 	 * but our hardware wants the pitch/stride to cover all rows included
62155bc277dSAlexandru Gheorghe 	 * in a tile.
62255bc277dSAlexandru Gheorghe 	 */
62355bc277dSAlexandru Gheorghe 	for (i = 0; i < num_strides; ++i) {
62455bc277dSAlexandru Gheorghe 		unsigned int block_h = drm_format_info_block_height(mp->base.state->fb->format, i);
62555bc277dSAlexandru Gheorghe 
62655bc277dSAlexandru Gheorghe 		malidp_hw_write(mp->hwdev, pitches[i] * block_h,
62783d642eeSMihail Atanassov 				mp->layer->base +
62883d642eeSMihail Atanassov 				mp->layer->stride_offset + i * 4);
62983d642eeSMihail Atanassov 	}
63055bc277dSAlexandru Gheorghe }
63183d642eeSMihail Atanassov 
6326e810eb5SMihail Atanassov static const s16
6336e810eb5SMihail Atanassov malidp_yuv2rgb_coeffs[][DRM_COLOR_RANGE_MAX][MALIDP_COLORADJ_NUM_COEFFS] = {
6346e810eb5SMihail Atanassov 	[DRM_COLOR_YCBCR_BT601][DRM_COLOR_YCBCR_LIMITED_RANGE] = {
6356e810eb5SMihail Atanassov 		1192,    0, 1634,
6366e810eb5SMihail Atanassov 		1192, -401, -832,
6376e810eb5SMihail Atanassov 		1192, 2066,    0,
6386e810eb5SMihail Atanassov 		  64,  512,  512
6396e810eb5SMihail Atanassov 	},
6406e810eb5SMihail Atanassov 	[DRM_COLOR_YCBCR_BT601][DRM_COLOR_YCBCR_FULL_RANGE] = {
6416e810eb5SMihail Atanassov 		1024,    0, 1436,
6426e810eb5SMihail Atanassov 		1024, -352, -731,
6436e810eb5SMihail Atanassov 		1024, 1815,    0,
6446e810eb5SMihail Atanassov 		   0,  512,  512
6456e810eb5SMihail Atanassov 	},
6466e810eb5SMihail Atanassov 	[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE] = {
6476e810eb5SMihail Atanassov 		1192,    0, 1836,
6486e810eb5SMihail Atanassov 		1192, -218, -546,
6496e810eb5SMihail Atanassov 		1192, 2163,    0,
6506e810eb5SMihail Atanassov 		  64,  512,  512
6516e810eb5SMihail Atanassov 	},
6526e810eb5SMihail Atanassov 	[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_FULL_RANGE] = {
6536e810eb5SMihail Atanassov 		1024,    0, 1613,
6546e810eb5SMihail Atanassov 		1024, -192, -479,
6556e810eb5SMihail Atanassov 		1024, 1900,    0,
6566e810eb5SMihail Atanassov 		   0,  512,  512
6576e810eb5SMihail Atanassov 	},
6586e810eb5SMihail Atanassov 	[DRM_COLOR_YCBCR_BT2020][DRM_COLOR_YCBCR_LIMITED_RANGE] = {
6596e810eb5SMihail Atanassov 		1024,    0, 1476,
6606e810eb5SMihail Atanassov 		1024, -165, -572,
6616e810eb5SMihail Atanassov 		1024, 1884,    0,
6626e810eb5SMihail Atanassov 		   0,  512,  512
6636e810eb5SMihail Atanassov 	},
6646e810eb5SMihail Atanassov 	[DRM_COLOR_YCBCR_BT2020][DRM_COLOR_YCBCR_FULL_RANGE] = {
6656e810eb5SMihail Atanassov 		1024,    0, 1510,
6666e810eb5SMihail Atanassov 		1024, -168, -585,
6676e810eb5SMihail Atanassov 		1024, 1927,    0,
6686e810eb5SMihail Atanassov 		   0,  512,  512
6696e810eb5SMihail Atanassov 	}
6706e810eb5SMihail Atanassov };
6716e810eb5SMihail Atanassov 
malidp_de_set_color_encoding(struct malidp_plane * plane,enum drm_color_encoding enc,enum drm_color_range range)6726e810eb5SMihail Atanassov static void malidp_de_set_color_encoding(struct malidp_plane *plane,
6736e810eb5SMihail Atanassov 					 enum drm_color_encoding enc,
6746e810eb5SMihail Atanassov 					 enum drm_color_range range)
6756e810eb5SMihail Atanassov {
6766e810eb5SMihail Atanassov 	unsigned int i;
6776e810eb5SMihail Atanassov 
6786e810eb5SMihail Atanassov 	for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
6796e810eb5SMihail Atanassov 		/* coefficients are signed, two's complement values */
6806e810eb5SMihail Atanassov 		malidp_hw_write(plane->hwdev, malidp_yuv2rgb_coeffs[enc][range][i],
6816e810eb5SMihail Atanassov 				plane->layer->base + plane->layer->yuv2rgb_offset +
6826e810eb5SMihail Atanassov 				i * 4);
6836e810eb5SMihail Atanassov 	}
6846e810eb5SMihail Atanassov }
6856e810eb5SMihail Atanassov 
malidp_de_set_mmu_control(struct malidp_plane * mp,struct malidp_plane_state * ms)6861f23a56aSJamie Fox static void malidp_de_set_mmu_control(struct malidp_plane *mp,
6871f23a56aSJamie Fox 				      struct malidp_plane_state *ms)
6881f23a56aSJamie Fox {
6891f23a56aSJamie Fox 	u32 mmu_ctrl;
6901f23a56aSJamie Fox 
6911f23a56aSJamie Fox 	/* check hardware supports MMU prefetch */
6921f23a56aSJamie Fox 	if (!mp->layer->mmu_ctrl_offset)
6931f23a56aSJamie Fox 		return;
6941f23a56aSJamie Fox 
6951f23a56aSJamie Fox 	mmu_ctrl = malidp_calc_mmu_control_value(ms->mmu_prefetch_mode,
6961f23a56aSJamie Fox 						 MALIDP_MMU_PREFETCH_READAHEAD,
6971f23a56aSJamie Fox 						 ms->n_planes,
6981f23a56aSJamie Fox 						 ms->mmu_prefetch_pgsize);
6991f23a56aSJamie Fox 
7001f23a56aSJamie Fox 	malidp_hw_write(mp->hwdev, mmu_ctrl,
7011f23a56aSJamie Fox 			mp->layer->base + mp->layer->mmu_ctrl_offset);
7021f23a56aSJamie Fox }
7031f23a56aSJamie Fox 
malidp_set_plane_base_addr(struct drm_framebuffer * fb,struct malidp_plane * mp,int plane_index)70454b4260aSAyan Kumar Halder static void malidp_set_plane_base_addr(struct drm_framebuffer *fb,
70554b4260aSAyan Kumar Halder 				       struct malidp_plane *mp,
70654b4260aSAyan Kumar Halder 				       int plane_index)
70754b4260aSAyan Kumar Halder {
7088c30eeccSDanilo Krummrich 	dma_addr_t dma_addr;
70954b4260aSAyan Kumar Halder 	u16 ptr;
71054b4260aSAyan Kumar Halder 	struct drm_plane *plane = &mp->base;
71154b4260aSAyan Kumar Halder 	bool afbc = fb->modifier ? true : false;
71254b4260aSAyan Kumar Halder 
71354b4260aSAyan Kumar Halder 	ptr = mp->layer->ptr + (plane_index << 4);
71454b4260aSAyan Kumar Halder 
71554b4260aSAyan Kumar Halder 	/*
7166bcfe8eaSDanilo Krummrich 	 * drm_fb_dma_get_gem_addr() alters the physical base address of the
71754b4260aSAyan Kumar Halder 	 * framebuffer as per the plane's src_x, src_y co-ordinates (ie to
71854b4260aSAyan Kumar Halder 	 * take care of source cropping).
71954b4260aSAyan Kumar Halder 	 * For AFBC, this is not needed as the cropping is handled by _AD_CROP_H
72054b4260aSAyan Kumar Halder 	 * and _AD_CROP_V registers.
72154b4260aSAyan Kumar Halder 	 */
72254b4260aSAyan Kumar Halder 	if (!afbc) {
7238c30eeccSDanilo Krummrich 		dma_addr = drm_fb_dma_get_gem_addr(fb, plane->state,
72454b4260aSAyan Kumar Halder 						   plane_index);
72554b4260aSAyan Kumar Halder 	} else {
7264a83c26aSDanilo Krummrich 		struct drm_gem_dma_object *obj;
72754b4260aSAyan Kumar Halder 
7286bcfe8eaSDanilo Krummrich 		obj = drm_fb_dma_get_gem_obj(fb, plane_index);
72954b4260aSAyan Kumar Halder 
73054b4260aSAyan Kumar Halder 		if (WARN_ON(!obj))
73154b4260aSAyan Kumar Halder 			return;
7328c30eeccSDanilo Krummrich 		dma_addr = obj->dma_addr;
73354b4260aSAyan Kumar Halder 	}
73454b4260aSAyan Kumar Halder 
7358c30eeccSDanilo Krummrich 	malidp_hw_write(mp->hwdev, lower_32_bits(dma_addr), ptr);
7368c30eeccSDanilo Krummrich 	malidp_hw_write(mp->hwdev, upper_32_bits(dma_addr), ptr + 4);
73754b4260aSAyan Kumar Halder }
73854b4260aSAyan Kumar Halder 
malidp_de_set_plane_afbc(struct drm_plane * plane)73954b4260aSAyan Kumar Halder static void malidp_de_set_plane_afbc(struct drm_plane *plane)
74054b4260aSAyan Kumar Halder {
74154b4260aSAyan Kumar Halder 	struct malidp_plane *mp;
74254b4260aSAyan Kumar Halder 	u32 src_w, src_h, val = 0, src_x, src_y;
74354b4260aSAyan Kumar Halder 	struct drm_framebuffer *fb = plane->state->fb;
74454b4260aSAyan Kumar Halder 
74554b4260aSAyan Kumar Halder 	mp = to_malidp_plane(plane);
74654b4260aSAyan Kumar Halder 
74754b4260aSAyan Kumar Halder 	/* no afbc_decoder_offset means AFBC is not supported on this plane */
74854b4260aSAyan Kumar Halder 	if (!mp->layer->afbc_decoder_offset)
74954b4260aSAyan Kumar Halder 		return;
75054b4260aSAyan Kumar Halder 
75154b4260aSAyan Kumar Halder 	if (!fb->modifier) {
75254b4260aSAyan Kumar Halder 		malidp_hw_write(mp->hwdev, 0, mp->layer->afbc_decoder_offset);
75354b4260aSAyan Kumar Halder 		return;
75454b4260aSAyan Kumar Halder 	}
75554b4260aSAyan Kumar Halder 
75654b4260aSAyan Kumar Halder 	/* convert src values from Q16 fixed point to integer */
75754b4260aSAyan Kumar Halder 	src_w = plane->state->src_w >> 16;
75854b4260aSAyan Kumar Halder 	src_h = plane->state->src_h >> 16;
75954b4260aSAyan Kumar Halder 	src_x = plane->state->src_x >> 16;
76054b4260aSAyan Kumar Halder 	src_y = plane->state->src_y >> 16;
76154b4260aSAyan Kumar Halder 
76254b4260aSAyan Kumar Halder 	val = ((fb->width - (src_x + src_w)) << MALIDP_AD_CROP_RIGHT_OFFSET) |
76354b4260aSAyan Kumar Halder 		   src_x;
76454b4260aSAyan Kumar Halder 	malidp_hw_write(mp->hwdev, val,
76554b4260aSAyan Kumar Halder 			mp->layer->afbc_decoder_offset + MALIDP_AD_CROP_H);
76654b4260aSAyan Kumar Halder 
76754b4260aSAyan Kumar Halder 	val = ((fb->height - (src_y + src_h)) << MALIDP_AD_CROP_BOTTOM_OFFSET) |
76854b4260aSAyan Kumar Halder 		   src_y;
76954b4260aSAyan Kumar Halder 	malidp_hw_write(mp->hwdev, val,
77054b4260aSAyan Kumar Halder 			mp->layer->afbc_decoder_offset + MALIDP_AD_CROP_V);
77154b4260aSAyan Kumar Halder 
77254b4260aSAyan Kumar Halder 	val = MALIDP_AD_EN;
77354b4260aSAyan Kumar Halder 	if (fb->modifier & AFBC_FORMAT_MOD_SPLIT)
77454b4260aSAyan Kumar Halder 		val |= MALIDP_AD_BS;
77554b4260aSAyan Kumar Halder 	if (fb->modifier & AFBC_FORMAT_MOD_YTR)
77654b4260aSAyan Kumar Halder 		val |= MALIDP_AD_YTR;
77754b4260aSAyan Kumar Halder 
77854b4260aSAyan Kumar Halder 	malidp_hw_write(mp->hwdev, val, mp->layer->afbc_decoder_offset);
77954b4260aSAyan Kumar Halder }
78054b4260aSAyan Kumar Halder 
malidp_de_plane_update(struct drm_plane * plane,struct drm_atomic_state * state)781ad49f860SLiviu Dudau static void malidp_de_plane_update(struct drm_plane *plane,
782977697e2SMaxime Ripard 				   struct drm_atomic_state *state)
783ad49f860SLiviu Dudau {
784977697e2SMaxime Ripard 	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
785977697e2SMaxime Ripard 									   plane);
786ad49f860SLiviu Dudau 	struct malidp_plane *mp;
78770c94a3cSBrian Starkey 	struct malidp_plane_state *ms = to_malidp_plane_state(plane->state);
78837418bf1SMaxime Ripard 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
78937418bf1SMaxime Ripard 									   plane);
79041016fe1SMaxime Ripard 	u16 pixel_alpha = new_state->pixel_blend_mode;
79141016fe1SMaxime Ripard 	u8 plane_alpha = new_state->alpha >> 8;
79270c94a3cSBrian Starkey 	u32 src_w, src_h, dest_w, dest_h, val;
79370c94a3cSBrian Starkey 	int i;
79454b4260aSAyan Kumar Halder 	struct drm_framebuffer *fb = plane->state->fb;
795ad49f860SLiviu Dudau 
796ad49f860SLiviu Dudau 	mp = to_malidp_plane(plane);
797ad49f860SLiviu Dudau 
79854b4260aSAyan Kumar Halder 	/*
79954b4260aSAyan Kumar Halder 	 * For AFBC framebuffer, use the framebuffer width and height for
80054b4260aSAyan Kumar Halder 	 * configuring layer input size register.
80154b4260aSAyan Kumar Halder 	 */
80254b4260aSAyan Kumar Halder 	if (fb->modifier) {
80354b4260aSAyan Kumar Halder 		src_w = fb->width;
80454b4260aSAyan Kumar Halder 		src_h = fb->height;
80554b4260aSAyan Kumar Halder 	} else {
806ad49f860SLiviu Dudau 		/* convert src values from Q16 fixed point to integer */
80741016fe1SMaxime Ripard 		src_w = new_state->src_w >> 16;
80841016fe1SMaxime Ripard 		src_h = new_state->src_h >> 16;
80954b4260aSAyan Kumar Halder 	}
81054b4260aSAyan Kumar Halder 
81141016fe1SMaxime Ripard 	dest_w = new_state->crtc_w;
81241016fe1SMaxime Ripard 	dest_h = new_state->crtc_h;
813ad49f860SLiviu Dudau 
814ad7fda2eSAyan Kumar Halder 	val = malidp_hw_read(mp->hwdev, mp->layer->base);
815ad7fda2eSAyan Kumar Halder 	val = (val & ~LAYER_FORMAT_MASK) | ms->format;
816ad7fda2eSAyan Kumar Halder 	malidp_hw_write(mp->hwdev, val, mp->layer->base);
817ad49f860SLiviu Dudau 
81854b4260aSAyan Kumar Halder 	for (i = 0; i < ms->n_planes; i++)
81954b4260aSAyan Kumar Halder 		malidp_set_plane_base_addr(fb, mp, i);
8201f23a56aSJamie Fox 
8211f23a56aSJamie Fox 	malidp_de_set_mmu_control(mp, ms);
8221f23a56aSJamie Fox 
82383d642eeSMihail Atanassov 	malidp_de_set_plane_pitches(mp, ms->n_planes,
82441016fe1SMaxime Ripard 				    new_state->fb->pitches);
825ad49f860SLiviu Dudau 
8266e810eb5SMihail Atanassov 	if ((plane->state->color_encoding != old_state->color_encoding) ||
8276e810eb5SMihail Atanassov 	    (plane->state->color_range != old_state->color_range))
8286e810eb5SMihail Atanassov 		malidp_de_set_color_encoding(mp, plane->state->color_encoding,
8296e810eb5SMihail Atanassov 					     plane->state->color_range);
8306e810eb5SMihail Atanassov 
831ad49f860SLiviu Dudau 	malidp_hw_write(mp->hwdev, LAYER_H_VAL(src_w) | LAYER_V_VAL(src_h),
832ad49f860SLiviu Dudau 			mp->layer->base + MALIDP_LAYER_SIZE);
833ad49f860SLiviu Dudau 
834ad49f860SLiviu Dudau 	malidp_hw_write(mp->hwdev, LAYER_H_VAL(dest_w) | LAYER_V_VAL(dest_h),
835ad49f860SLiviu Dudau 			mp->layer->base + MALIDP_LAYER_COMP_SIZE);
836ad49f860SLiviu Dudau 
83741016fe1SMaxime Ripard 	malidp_hw_write(mp->hwdev, LAYER_H_VAL(new_state->crtc_x) |
83841016fe1SMaxime Ripard 			LAYER_V_VAL(new_state->crtc_y),
839ad49f860SLiviu Dudau 			mp->layer->base + MALIDP_LAYER_OFFSET);
840ad49f860SLiviu Dudau 
841791d54faSAlexandru Gheorghe 	if (mp->layer->id == DE_SMART) {
842791d54faSAlexandru Gheorghe 		/*
843791d54faSAlexandru Gheorghe 		 * Enable the first rectangle in the SMART layer to be
844791d54faSAlexandru Gheorghe 		 * able to use it as a drm plane.
845791d54faSAlexandru Gheorghe 		 */
846791d54faSAlexandru Gheorghe 		malidp_hw_write(mp->hwdev, 1,
847791d54faSAlexandru Gheorghe 				mp->layer->base + MALIDP550_LS_ENABLE);
848d1479f61SMihail Atanassov 		malidp_hw_write(mp->hwdev,
849d1479f61SMihail Atanassov 				LAYER_H_VAL(src_w) | LAYER_V_VAL(src_h),
850d1479f61SMihail Atanassov 				mp->layer->base + MALIDP550_LS_R1_IN_SIZE);
851791d54faSAlexandru Gheorghe 	}
852d1479f61SMihail Atanassov 
85354b4260aSAyan Kumar Halder 	malidp_de_set_plane_afbc(plane);
85454b4260aSAyan Kumar Halder 
855c57eb710SBrian Starkey 	/* first clear the rotation bits */
856c57eb710SBrian Starkey 	val = malidp_hw_read(mp->hwdev, mp->layer->base + MALIDP_LAYER_CONTROL);
857c57eb710SBrian Starkey 	val &= ~LAYER_ROT_MASK;
858ad49f860SLiviu Dudau 
859ad49f860SLiviu Dudau 	/* setup the rotation and axis flip bits */
86041016fe1SMaxime Ripard 	if (new_state->rotation & DRM_MODE_ROTATE_MASK)
861c2c446adSRobert Foss 		val |= ilog2(plane->state->rotation & DRM_MODE_ROTATE_MASK) <<
862c7ffa59cSMihail Atanassov 		       LAYER_ROT_OFFSET;
86341016fe1SMaxime Ripard 	if (new_state->rotation & DRM_MODE_REFLECT_X)
864ad49f860SLiviu Dudau 		val |= LAYER_H_FLIP;
86541016fe1SMaxime Ripard 	if (new_state->rotation & DRM_MODE_REFLECT_Y)
8667916efe5SBrian Starkey 		val |= LAYER_V_FLIP;
867ad49f860SLiviu Dudau 
868187f7f21SLowry Li 	val &= ~(LAYER_COMP_MASK | LAYER_PMUL_ENABLE | LAYER_ALPHA(0xff));
869f0437819SAyan Halder 
87041016fe1SMaxime Ripard 	if (new_state->alpha != DRM_BLEND_ALPHA_OPAQUE) {
871f0437819SAyan Halder 		val |= LAYER_COMP_PLANE;
87241016fe1SMaxime Ripard 	} else if (new_state->fb->format->has_alpha) {
873187f7f21SLowry Li 		/* We only care about blend mode if the format has alpha */
874187f7f21SLowry Li 		switch (pixel_alpha) {
875187f7f21SLowry Li 		case DRM_MODE_BLEND_PREMULTI:
876187f7f21SLowry Li 			val |= LAYER_COMP_PIXEL | LAYER_PMUL_ENABLE;
877187f7f21SLowry Li 			break;
878187f7f21SLowry Li 		case DRM_MODE_BLEND_COVERAGE:
879187f7f21SLowry Li 			val |= LAYER_COMP_PIXEL;
880187f7f21SLowry Li 			break;
881f0437819SAyan Halder 		}
882187f7f21SLowry Li 	}
883187f7f21SLowry Li 	val |= LAYER_ALPHA(plane_alpha);
884c57eb710SBrian Starkey 
88528ce675bSMihail Atanassov 	val &= ~LAYER_FLOWCFG(LAYER_FLOWCFG_MASK);
88641016fe1SMaxime Ripard 	if (new_state->crtc) {
88728ce675bSMihail Atanassov 		struct malidp_crtc_state *m =
88841016fe1SMaxime Ripard 			to_malidp_crtc_state(new_state->crtc->state);
88928ce675bSMihail Atanassov 
89028ce675bSMihail Atanassov 		if (m->scaler_config.scale_enable &&
89128ce675bSMihail Atanassov 		    m->scaler_config.plane_src_id == mp->layer->id)
89228ce675bSMihail Atanassov 			val |= LAYER_FLOWCFG(LAYER_FLOWCFG_SCALE_SE);
89328ce675bSMihail Atanassov 	}
89428ce675bSMihail Atanassov 
895ad49f860SLiviu Dudau 	/* set the 'enable layer' bit */
896ad49f860SLiviu Dudau 	val |= LAYER_ENABLE;
897ad49f860SLiviu Dudau 
898c57eb710SBrian Starkey 	malidp_hw_write(mp->hwdev, val,
899ad49f860SLiviu Dudau 			mp->layer->base + MALIDP_LAYER_CONTROL);
900ad49f860SLiviu Dudau }
901ad49f860SLiviu Dudau 
malidp_de_plane_disable(struct drm_plane * plane,struct drm_atomic_state * state)902ad49f860SLiviu Dudau static void malidp_de_plane_disable(struct drm_plane *plane,
903977697e2SMaxime Ripard 				    struct drm_atomic_state *state)
904ad49f860SLiviu Dudau {
905ad49f860SLiviu Dudau 	struct malidp_plane *mp = to_malidp_plane(plane);
906ad49f860SLiviu Dudau 
90728ce675bSMihail Atanassov 	malidp_hw_clearbits(mp->hwdev,
90828ce675bSMihail Atanassov 			    LAYER_ENABLE | LAYER_FLOWCFG(LAYER_FLOWCFG_MASK),
909ad49f860SLiviu Dudau 			    mp->layer->base + MALIDP_LAYER_CONTROL);
910ad49f860SLiviu Dudau }
911ad49f860SLiviu Dudau 
912ad49f860SLiviu Dudau static const struct drm_plane_helper_funcs malidp_de_plane_helper_funcs = {
913ad49f860SLiviu Dudau 	.atomic_check = malidp_de_plane_check,
914ad49f860SLiviu Dudau 	.atomic_update = malidp_de_plane_update,
915ad49f860SLiviu Dudau 	.atomic_disable = malidp_de_plane_disable,
916ad49f860SLiviu Dudau };
917ad49f860SLiviu Dudau 
91826c3e7fdSDaniel Vetter static const uint64_t linear_only_modifiers[] = {
91926c3e7fdSDaniel Vetter 	DRM_FORMAT_MOD_LINEAR,
92026c3e7fdSDaniel Vetter 	DRM_FORMAT_MOD_INVALID
92126c3e7fdSDaniel Vetter };
92226c3e7fdSDaniel Vetter 
malidp_de_planes_init(struct drm_device * drm)923ad49f860SLiviu Dudau int malidp_de_planes_init(struct drm_device *drm)
924ad49f860SLiviu Dudau {
9251b93d3cbSDanilo Krummrich 	struct malidp_drm *malidp = drm_to_malidp(drm);
926a6993b21SLiviu Dudau 	const struct malidp_hw_regmap *map = &malidp->dev->hw->map;
927ad49f860SLiviu Dudau 	struct malidp_plane *plane = NULL;
928ad49f860SLiviu Dudau 	enum drm_plane_type plane_type;
9295f368ddeSColin Ian King 	unsigned long crtcs = BIT(drm->mode_config.num_crtc);
930c2c446adSRobert Foss 	unsigned long flags = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_180 |
931c2c446adSRobert Foss 			      DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y;
932187f7f21SLowry Li 	unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
933187f7f21SLowry Li 				  BIT(DRM_MODE_BLEND_PREMULTI)   |
934187f7f21SLowry Li 				  BIT(DRM_MODE_BLEND_COVERAGE);
935ad49f860SLiviu Dudau 	u32 *formats;
93625570b5eSAyan Kumar Halder 	int ret, i = 0, j = 0, n;
93725570b5eSAyan Kumar Halder 	u64 supported_modifiers[MODIFIERS_COUNT_MAX];
93825570b5eSAyan Kumar Halder 	const u64 *modifiers;
93925570b5eSAyan Kumar Halder 
94025570b5eSAyan Kumar Halder 	modifiers = malidp_format_modifiers;
94125570b5eSAyan Kumar Halder 
94225570b5eSAyan Kumar Halder 	if (!(map->features & MALIDP_DEVICE_AFBC_SUPPORT_SPLIT)) {
94325570b5eSAyan Kumar Halder 		/*
94425570b5eSAyan Kumar Halder 		 * Since our hardware does not support SPLIT, so build the list
94525570b5eSAyan Kumar Halder 		 * of supported modifiers excluding SPLIT ones.
94625570b5eSAyan Kumar Halder 		 */
94725570b5eSAyan Kumar Halder 		while (*modifiers != DRM_FORMAT_MOD_INVALID) {
94825570b5eSAyan Kumar Halder 			if (!(*modifiers & AFBC_SPLIT))
94925570b5eSAyan Kumar Halder 				supported_modifiers[j++] = *modifiers;
95025570b5eSAyan Kumar Halder 
95125570b5eSAyan Kumar Halder 			modifiers++;
95225570b5eSAyan Kumar Halder 		}
95325570b5eSAyan Kumar Halder 		supported_modifiers[j++] = DRM_FORMAT_MOD_INVALID;
95425570b5eSAyan Kumar Halder 		modifiers = supported_modifiers;
95525570b5eSAyan Kumar Halder 	}
956ad49f860SLiviu Dudau 
9576211b486SBrian Starkey 	formats = kcalloc(map->n_pixel_formats, sizeof(*formats), GFP_KERNEL);
958ad49f860SLiviu Dudau 	if (!formats) {
959ad49f860SLiviu Dudau 		ret = -ENOMEM;
960ad49f860SLiviu Dudau 		goto cleanup;
961ad49f860SLiviu Dudau 	}
962ad49f860SLiviu Dudau 
963ad49f860SLiviu Dudau 	for (i = 0; i < map->n_layers; i++) {
964ad49f860SLiviu Dudau 		u8 id = map->layers[i].id;
965ad49f860SLiviu Dudau 
966ad49f860SLiviu Dudau 		/* build the list of DRM supported formats based on the map */
9676211b486SBrian Starkey 		for (n = 0, j = 0;  j < map->n_pixel_formats; j++) {
9686211b486SBrian Starkey 			if ((map->pixel_formats[j].layer & id) == id)
9696211b486SBrian Starkey 				formats[n++] = map->pixel_formats[j].format;
970ad49f860SLiviu Dudau 		}
971ad49f860SLiviu Dudau 
972ad49f860SLiviu Dudau 		plane_type = (i == 0) ? DRM_PLANE_TYPE_PRIMARY :
973ad49f860SLiviu Dudau 					DRM_PLANE_TYPE_OVERLAY;
97425570b5eSAyan Kumar Halder 
97525570b5eSAyan Kumar Halder 		/*
97625570b5eSAyan Kumar Halder 		 * All the layers except smart layer supports AFBC modifiers.
97725570b5eSAyan Kumar Halder 		 */
978*3ad51034SDanilo Krummrich 		plane = drmm_universal_plane_alloc(drm, struct malidp_plane, base,
979*3ad51034SDanilo Krummrich 						   crtcs, &malidp_de_plane_funcs, formats, n,
980*3ad51034SDanilo Krummrich 						   (id == DE_SMART) ? linear_only_modifiers :
981*3ad51034SDanilo Krummrich 						   modifiers, plane_type, NULL);
982*3ad51034SDanilo Krummrich 		if (IS_ERR(plane)) {
983*3ad51034SDanilo Krummrich 			ret = PTR_ERR(plane);
984ad49f860SLiviu Dudau 			goto cleanup;
985*3ad51034SDanilo Krummrich 		}
986ad49f860SLiviu Dudau 
987ad49f860SLiviu Dudau 		drm_plane_helper_add(&plane->base,
988ad49f860SLiviu Dudau 				     &malidp_de_plane_helper_funcs);
989ad49f860SLiviu Dudau 		plane->hwdev = malidp->dev;
990ad49f860SLiviu Dudau 		plane->layer = &map->layers[i];
99115807780SBrian Starkey 
992187f7f21SLowry Li 		drm_plane_create_alpha_property(&plane->base);
993187f7f21SLowry Li 		drm_plane_create_blend_mode_property(&plane->base, blend_caps);
994187f7f21SLowry Li 
995d1479f61SMihail Atanassov 		if (id == DE_SMART) {
996d1479f61SMihail Atanassov 			/* Skip the features which the SMART layer doesn't have. */
99715807780SBrian Starkey 			continue;
998d1479f61SMihail Atanassov 		}
99915807780SBrian Starkey 
1000c2c446adSRobert Foss 		drm_plane_create_rotation_property(&plane->base, DRM_MODE_ROTATE_0, flags);
1001c57eb710SBrian Starkey 		malidp_hw_write(malidp->dev, MALIDP_ALPHA_LUT,
1002c57eb710SBrian Starkey 				plane->layer->base + MALIDP_LAYER_COMPOSE);
10036e810eb5SMihail Atanassov 
10046e810eb5SMihail Atanassov 		/* Attach the YUV->RGB property only to video layers */
10056e810eb5SMihail Atanassov 		if (id & (DE_VIDEO1 | DE_VIDEO2)) {
10066e810eb5SMihail Atanassov 			/* default encoding for YUV->RGB is BT601 NARROW */
10076e810eb5SMihail Atanassov 			enum drm_color_encoding enc = DRM_COLOR_YCBCR_BT601;
10086e810eb5SMihail Atanassov 			enum drm_color_range range = DRM_COLOR_YCBCR_LIMITED_RANGE;
10096e810eb5SMihail Atanassov 
10106e810eb5SMihail Atanassov 			ret = drm_plane_create_color_properties(&plane->base,
10116e810eb5SMihail Atanassov 					BIT(DRM_COLOR_YCBCR_BT601) | \
10126e810eb5SMihail Atanassov 					BIT(DRM_COLOR_YCBCR_BT709) | \
10136e810eb5SMihail Atanassov 					BIT(DRM_COLOR_YCBCR_BT2020),
10146e810eb5SMihail Atanassov 					BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | \
10156e810eb5SMihail Atanassov 					BIT(DRM_COLOR_YCBCR_FULL_RANGE),
10166e810eb5SMihail Atanassov 					enc, range);
10176e810eb5SMihail Atanassov 			if (!ret)
10186e810eb5SMihail Atanassov 				/* program the HW registers */
10196e810eb5SMihail Atanassov 				malidp_de_set_color_encoding(plane, enc, range);
10206e810eb5SMihail Atanassov 			else
10216e810eb5SMihail Atanassov 				DRM_WARN("Failed to create video layer %d color properties\n", id);
10226e810eb5SMihail Atanassov 		}
1023ad49f860SLiviu Dudau 	}
1024ad49f860SLiviu Dudau 
1025ad49f860SLiviu Dudau 	kfree(formats);
1026ad49f860SLiviu Dudau 
1027ad49f860SLiviu Dudau 	return 0;
1028ad49f860SLiviu Dudau 
1029ad49f860SLiviu Dudau cleanup:
1030ad49f860SLiviu Dudau 	kfree(formats);
1031ad49f860SLiviu Dudau 
1032ad49f860SLiviu Dudau 	return ret;
1033ad49f860SLiviu Dudau }
1034