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 DP500/DP550/DP650 hardware manipulation routines. This is where
762306a36Sopenharmony_ci * the difference between various versions of the hardware is being dealt with
862306a36Sopenharmony_ci * in an attempt to provide to the rest of the driver code a unified view
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/clk.h>
1262306a36Sopenharmony_ci#include <linux/delay.h>
1362306a36Sopenharmony_ci#include <linux/types.h>
1462306a36Sopenharmony_ci#include <linux/io.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <video/videomode.h>
1762306a36Sopenharmony_ci#include <video/display_timing.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <drm/drm_fourcc.h>
2062306a36Sopenharmony_ci#include <drm/drm_vblank.h>
2162306a36Sopenharmony_ci#include <drm/drm_print.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "malidp_drv.h"
2462306a36Sopenharmony_ci#include "malidp_hw.h"
2562306a36Sopenharmony_ci#include "malidp_mw.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cienum {
2862306a36Sopenharmony_ci	MW_NOT_ENABLED = 0,	/* SE writeback not enabled */
2962306a36Sopenharmony_ci	MW_ONESHOT,		/* SE in one-shot mode for writeback */
3062306a36Sopenharmony_ci	MW_START,		/* SE started writeback */
3162306a36Sopenharmony_ci	MW_RESTART,		/* SE will start another writeback after this one */
3262306a36Sopenharmony_ci	MW_STOP,		/* SE needs to stop after this writeback */
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic const struct malidp_format_id malidp500_de_formats[] = {
3662306a36Sopenharmony_ci	/*    fourcc,   layers supporting the format,     internal id  */
3762306a36Sopenharmony_ci	{ DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  0 },
3862306a36Sopenharmony_ci	{ DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  1 },
3962306a36Sopenharmony_ci	{ DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  2 },
4062306a36Sopenharmony_ci	{ DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  3 },
4162306a36Sopenharmony_ci	{ DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  4 },
4262306a36Sopenharmony_ci	{ DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  5 },
4362306a36Sopenharmony_ci	{ DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  6 },
4462306a36Sopenharmony_ci	{ DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  7 },
4562306a36Sopenharmony_ci	{ DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  8 },
4662306a36Sopenharmony_ci	{ DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  9 },
4762306a36Sopenharmony_ci	{ DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 },
4862306a36Sopenharmony_ci	{ DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 },
4962306a36Sopenharmony_ci	{ DRM_FORMAT_UYVY, DE_VIDEO1, 12 },
5062306a36Sopenharmony_ci	{ DRM_FORMAT_YUYV, DE_VIDEO1, 13 },
5162306a36Sopenharmony_ci	{ DRM_FORMAT_NV12, DE_VIDEO1 | SE_MEMWRITE, 14 },
5262306a36Sopenharmony_ci	{ DRM_FORMAT_YUV420, DE_VIDEO1, 15 },
5362306a36Sopenharmony_ci	{ DRM_FORMAT_XYUV8888, DE_VIDEO1, 16 },
5462306a36Sopenharmony_ci	/* These are supported with AFBC only */
5562306a36Sopenharmony_ci	{ DRM_FORMAT_YUV420_8BIT, DE_VIDEO1, 14 },
5662306a36Sopenharmony_ci	{ DRM_FORMAT_VUY888, DE_VIDEO1, 16 },
5762306a36Sopenharmony_ci	{ DRM_FORMAT_VUY101010, DE_VIDEO1, 17 },
5862306a36Sopenharmony_ci	{ DRM_FORMAT_YUV420_10BIT, DE_VIDEO1, 18 }
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define MALIDP_ID(__group, __format) \
6262306a36Sopenharmony_ci	((((__group) & 0x7) << 3) | ((__format) & 0x7))
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define AFBC_YUV_422_FORMAT_ID	MALIDP_ID(5, 1)
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define MALIDP_COMMON_FORMATS \
6762306a36Sopenharmony_ci	/*    fourcc,   layers supporting the format,      internal id   */ \
6862306a36Sopenharmony_ci	{ DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 0) }, \
6962306a36Sopenharmony_ci	{ DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 1) }, \
7062306a36Sopenharmony_ci	{ DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 2) }, \
7162306a36Sopenharmony_ci	{ DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 3) }, \
7262306a36Sopenharmony_ci	{ DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \
7362306a36Sopenharmony_ci	{ DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \
7462306a36Sopenharmony_ci	{ DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \
7562306a36Sopenharmony_ci	{ DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \
7662306a36Sopenharmony_ci	{ DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 0) }, \
7762306a36Sopenharmony_ci	{ DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 1) }, \
7862306a36Sopenharmony_ci	{ DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 2) }, \
7962306a36Sopenharmony_ci	{ DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 3) }, \
8062306a36Sopenharmony_ci	{ DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(3, 0) }, \
8162306a36Sopenharmony_ci	{ DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(3, 1) }, \
8262306a36Sopenharmony_ci	{ DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \
8362306a36Sopenharmony_ci	{ DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \
8462306a36Sopenharmony_ci	{ DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \
8562306a36Sopenharmony_ci	{ DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \
8662306a36Sopenharmony_ci	/* This is only supported with linear modifier */	\
8762306a36Sopenharmony_ci	{ DRM_FORMAT_XYUV8888, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 0) },\
8862306a36Sopenharmony_ci	/* This is only supported with AFBC modifier */		\
8962306a36Sopenharmony_ci	{ DRM_FORMAT_VUY888, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 0) }, \
9062306a36Sopenharmony_ci	{ DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) },	\
9162306a36Sopenharmony_ci	/* This is only supported with linear modifier */ \
9262306a36Sopenharmony_ci	{ DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) },	\
9362306a36Sopenharmony_ci	{ DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(5, 6) },	\
9462306a36Sopenharmony_ci	/* This is only supported with AFBC modifier */ \
9562306a36Sopenharmony_ci	{ DRM_FORMAT_YUV420_8BIT, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) }, \
9662306a36Sopenharmony_ci	{ DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }, \
9762306a36Sopenharmony_ci	/* This is only supported with linear modifier */ \
9862306a36Sopenharmony_ci	{ DRM_FORMAT_XVYU2101010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 0)}, \
9962306a36Sopenharmony_ci	/* This is only supported with AFBC modifier */ \
10062306a36Sopenharmony_ci	{ DRM_FORMAT_VUY101010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 0)}, \
10162306a36Sopenharmony_ci	{ DRM_FORMAT_X0L2, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 6)}, \
10262306a36Sopenharmony_ci	/* This is only supported with AFBC modifier */ \
10362306a36Sopenharmony_ci	{ DRM_FORMAT_YUV420_10BIT, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 7)}, \
10462306a36Sopenharmony_ci	{ DRM_FORMAT_P010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 7)}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic const struct malidp_format_id malidp550_de_formats[] = {
10762306a36Sopenharmony_ci	MALIDP_COMMON_FORMATS,
10862306a36Sopenharmony_ci};
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic const struct malidp_format_id malidp650_de_formats[] = {
11162306a36Sopenharmony_ci	MALIDP_COMMON_FORMATS,
11262306a36Sopenharmony_ci	{ DRM_FORMAT_X0L0, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 4)},
11362306a36Sopenharmony_ci};
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic const struct malidp_layer malidp500_layers[] = {
11662306a36Sopenharmony_ci	/* id, base address, fb pointer address base, stride offset,
11762306a36Sopenharmony_ci	 *	yuv2rgb matrix offset, mmu control register offset, rotation_features
11862306a36Sopenharmony_ci	 */
11962306a36Sopenharmony_ci	{ DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE,
12062306a36Sopenharmony_ci		MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB, 0, ROTATE_ANY,
12162306a36Sopenharmony_ci		MALIDP500_DE_LV_AD_CTRL },
12262306a36Sopenharmony_ci	{ DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE,
12362306a36Sopenharmony_ci		MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY,
12462306a36Sopenharmony_ci		MALIDP500_DE_LG1_AD_CTRL },
12562306a36Sopenharmony_ci	{ DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE,
12662306a36Sopenharmony_ci		MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY,
12762306a36Sopenharmony_ci		MALIDP500_DE_LG2_AD_CTRL },
12862306a36Sopenharmony_ci};
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic const struct malidp_layer malidp550_layers[] = {
13162306a36Sopenharmony_ci	/* id, base address, fb pointer address base, stride offset,
13262306a36Sopenharmony_ci	 *	yuv2rgb matrix offset, mmu control register offset, rotation_features
13362306a36Sopenharmony_ci	 */
13462306a36Sopenharmony_ci	{ DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
13562306a36Sopenharmony_ci		MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY,
13662306a36Sopenharmony_ci		MALIDP550_DE_LV1_AD_CTRL },
13762306a36Sopenharmony_ci	{ DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
13862306a36Sopenharmony_ci		MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY,
13962306a36Sopenharmony_ci		MALIDP550_DE_LG_AD_CTRL },
14062306a36Sopenharmony_ci	{ DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
14162306a36Sopenharmony_ci		MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY,
14262306a36Sopenharmony_ci		MALIDP550_DE_LV2_AD_CTRL },
14362306a36Sopenharmony_ci	{ DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
14462306a36Sopenharmony_ci		MALIDP550_DE_LS_R1_STRIDE, 0, 0, ROTATE_NONE, 0 },
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic const struct malidp_layer malidp650_layers[] = {
14862306a36Sopenharmony_ci	/* id, base address, fb pointer address base, stride offset,
14962306a36Sopenharmony_ci	 *	yuv2rgb matrix offset, mmu control register offset,
15062306a36Sopenharmony_ci	 *	rotation_features
15162306a36Sopenharmony_ci	 */
15262306a36Sopenharmony_ci	{ DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
15362306a36Sopenharmony_ci		MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
15462306a36Sopenharmony_ci		MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY,
15562306a36Sopenharmony_ci		MALIDP550_DE_LV1_AD_CTRL },
15662306a36Sopenharmony_ci	{ DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
15762306a36Sopenharmony_ci		MALIDP_DE_LG_STRIDE, 0, MALIDP650_DE_LG_MMU_CTRL,
15862306a36Sopenharmony_ci		ROTATE_COMPRESSED, MALIDP550_DE_LG_AD_CTRL },
15962306a36Sopenharmony_ci	{ DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
16062306a36Sopenharmony_ci		MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
16162306a36Sopenharmony_ci		MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY,
16262306a36Sopenharmony_ci		MALIDP550_DE_LV2_AD_CTRL },
16362306a36Sopenharmony_ci	{ DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
16462306a36Sopenharmony_ci		MALIDP550_DE_LS_R1_STRIDE, 0, MALIDP650_DE_LS_MMU_CTRL,
16562306a36Sopenharmony_ci		ROTATE_NONE, 0 },
16662306a36Sopenharmony_ci};
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ciconst u64 malidp_format_modifiers[] = {
16962306a36Sopenharmony_ci	/* All RGB formats (except XRGB, RGBX, XBGR, BGRX) */
17062306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR | AFBC_SPARSE),
17162306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR),
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	/* All RGB formats > 16bpp (except XRGB, RGBX, XBGR, BGRX) */
17462306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR | AFBC_SPARSE | AFBC_SPLIT),
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	/* All 8 or 10 bit YUV 444 formats. */
17762306a36Sopenharmony_ci	/* In DP550, 10 bit YUV 420 format also supported */
17862306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_SPARSE | AFBC_SPLIT),
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	/* YUV 420, 422 P1 8 bit and YUV 444 8 bit/10 bit formats */
18162306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_SPARSE),
18262306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16),
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/* YUV 420, 422 P1 8, 10 bit formats */
18562306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_CBR | AFBC_SPARSE),
18662306a36Sopenharmony_ci	DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_CBR),
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/* All formats */
18962306a36Sopenharmony_ci	DRM_FORMAT_MOD_LINEAR,
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	DRM_FORMAT_MOD_INVALID
19262306a36Sopenharmony_ci};
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci#define SE_N_SCALING_COEFFS	96
19562306a36Sopenharmony_cistatic const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = {
19662306a36Sopenharmony_ci	[MALIDP_UPSCALING_COEFFS - 1] = {
19762306a36Sopenharmony_ci		0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052,
19862306a36Sopenharmony_ci		0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f,
19962306a36Sopenharmony_ci		0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a,
20062306a36Sopenharmony_ci		0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40,
20162306a36Sopenharmony_ci		0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c,
20262306a36Sopenharmony_ci		0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5,
20362306a36Sopenharmony_ci		0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15,
20462306a36Sopenharmony_ci		0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5,
20562306a36Sopenharmony_ci		0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0,
20662306a36Sopenharmony_ci		0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6,
20762306a36Sopenharmony_ci		0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073,
20862306a36Sopenharmony_ci		0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001
20962306a36Sopenharmony_ci	},
21062306a36Sopenharmony_ci	[MALIDP_DOWNSCALING_1_5_COEFFS - 1] = {
21162306a36Sopenharmony_ci		0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4,
21262306a36Sopenharmony_ci		0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c,
21362306a36Sopenharmony_ci		0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5,
21462306a36Sopenharmony_ci		0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8,
21562306a36Sopenharmony_ci		0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba,
21662306a36Sopenharmony_ci		0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20,
21762306a36Sopenharmony_ci		0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03,
21862306a36Sopenharmony_ci		0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d,
21962306a36Sopenharmony_ci		0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68,
22062306a36Sopenharmony_ci		0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f,
22162306a36Sopenharmony_ci		0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62,
22262306a36Sopenharmony_ci		0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f
22362306a36Sopenharmony_ci	},
22462306a36Sopenharmony_ci	[MALIDP_DOWNSCALING_2_COEFFS - 1] = {
22562306a36Sopenharmony_ci		0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9,
22662306a36Sopenharmony_ci		0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52,
22762306a36Sopenharmony_ci		0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158,
22862306a36Sopenharmony_ci		0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455,
22962306a36Sopenharmony_ci		0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e,
23062306a36Sopenharmony_ci		0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887,
23162306a36Sopenharmony_ci		0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5,
23262306a36Sopenharmony_ci		0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e,
23362306a36Sopenharmony_ci		0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d,
23462306a36Sopenharmony_ci		0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0,
23562306a36Sopenharmony_ci		0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf,
23662306a36Sopenharmony_ci		0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03
23762306a36Sopenharmony_ci	},
23862306a36Sopenharmony_ci	[MALIDP_DOWNSCALING_2_75_COEFFS - 1] = {
23962306a36Sopenharmony_ci		0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3,
24062306a36Sopenharmony_ci		0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106,
24162306a36Sopenharmony_ci		0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280,
24262306a36Sopenharmony_ci		0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410,
24362306a36Sopenharmony_ci		0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533,
24462306a36Sopenharmony_ci		0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3,
24562306a36Sopenharmony_ci		0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566,
24662306a36Sopenharmony_ci		0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468,
24762306a36Sopenharmony_ci		0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4,
24862306a36Sopenharmony_ci		0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160,
24962306a36Sopenharmony_ci		0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f,
25062306a36Sopenharmony_ci		0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60
25162306a36Sopenharmony_ci	},
25262306a36Sopenharmony_ci	[MALIDP_DOWNSCALING_4_COEFFS - 1] = {
25362306a36Sopenharmony_ci		0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f,
25462306a36Sopenharmony_ci		0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff,
25562306a36Sopenharmony_ci		0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd,
25662306a36Sopenharmony_ci		0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374,
25762306a36Sopenharmony_ci		0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db,
25862306a36Sopenharmony_ci		0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a,
25962306a36Sopenharmony_ci		0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed,
26062306a36Sopenharmony_ci		0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397,
26162306a36Sopenharmony_ci		0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb,
26262306a36Sopenharmony_ci		0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233,
26362306a36Sopenharmony_ci		0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160,
26462306a36Sopenharmony_ci		0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9
26562306a36Sopenharmony_ci	},
26662306a36Sopenharmony_ci};
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci#define MALIDP_DE_DEFAULT_PREFETCH_START	5
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic int malidp500_query_hw(struct malidp_hw_device *hwdev)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID);
27362306a36Sopenharmony_ci	/* bit 4 of the CONFIG_ID register holds the line size multiplier */
27462306a36Sopenharmony_ci	u8 ln_size_mult = conf & 0x10 ? 2 : 1;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	hwdev->min_line_size = 2;
27762306a36Sopenharmony_ci	hwdev->max_line_size = SZ_2K * ln_size_mult;
27862306a36Sopenharmony_ci	hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult;
27962306a36Sopenharmony_ci	hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	return 0;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic void malidp500_enter_config_mode(struct malidp_hw_device *hwdev)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	u32 status, count = 100;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
28962306a36Sopenharmony_ci	while (count) {
29062306a36Sopenharmony_ci		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
29162306a36Sopenharmony_ci		if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
29262306a36Sopenharmony_ci			break;
29362306a36Sopenharmony_ci		/*
29462306a36Sopenharmony_ci		 * entering config mode can take as long as the rendering
29562306a36Sopenharmony_ci		 * of a full frame, hence the long sleep here
29662306a36Sopenharmony_ci		 */
29762306a36Sopenharmony_ci		usleep_range(1000, 10000);
29862306a36Sopenharmony_ci		count--;
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci	WARN(count == 0, "timeout while entering config mode");
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	u32 status, count = 100;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
30862306a36Sopenharmony_ci	malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
30962306a36Sopenharmony_ci	while (count) {
31062306a36Sopenharmony_ci		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
31162306a36Sopenharmony_ci		if ((status & MALIDP500_DC_CONFIG_REQ) == 0)
31262306a36Sopenharmony_ci			break;
31362306a36Sopenharmony_ci		usleep_range(100, 1000);
31462306a36Sopenharmony_ci		count--;
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci	WARN(count == 0, "timeout while leaving config mode");
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	u32 status;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
32462306a36Sopenharmony_ci	if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
32562306a36Sopenharmony_ci		return true;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	return false;
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic void malidp500_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	if (value)
33362306a36Sopenharmony_ci		malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
33462306a36Sopenharmony_ci	else
33562306a36Sopenharmony_ci		malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	u32 val = 0;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	malidp_hw_write(hwdev, hwdev->output_color_depth,
34362306a36Sopenharmony_ci		hwdev->hw->map.out_depth_base);
34462306a36Sopenharmony_ci	malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL);
34562306a36Sopenharmony_ci	if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
34662306a36Sopenharmony_ci		val |= MALIDP500_HSYNCPOL;
34762306a36Sopenharmony_ci	if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
34862306a36Sopenharmony_ci		val |= MALIDP500_VSYNCPOL;
34962306a36Sopenharmony_ci	val |= MALIDP_DE_DEFAULT_PREFETCH_START;
35062306a36Sopenharmony_ci	malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	/*
35362306a36Sopenharmony_ci	 * Mali-DP500 encodes the background color like this:
35462306a36Sopenharmony_ci	 *    - red   @ MALIDP500_BGND_COLOR[12:0]
35562306a36Sopenharmony_ci	 *    - green @ MALIDP500_BGND_COLOR[27:16]
35662306a36Sopenharmony_ci	 *    - blue  @ (MALIDP500_BGND_COLOR + 4)[12:0]
35762306a36Sopenharmony_ci	 */
35862306a36Sopenharmony_ci	val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) |
35962306a36Sopenharmony_ci	      (MALIDP_BGND_COLOR_R & 0xfff);
36062306a36Sopenharmony_ci	malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR);
36162306a36Sopenharmony_ci	malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
36462306a36Sopenharmony_ci		MALIDP_DE_H_BACKPORCH(mode->hback_porch);
36562306a36Sopenharmony_ci	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) |
36862306a36Sopenharmony_ci		MALIDP_DE_V_BACKPORCH(mode->vback_porch);
36962306a36Sopenharmony_ci	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
37262306a36Sopenharmony_ci		MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
37362306a36Sopenharmony_ci	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
37662306a36Sopenharmony_ci	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	if (mode->flags & DISPLAY_FLAGS_INTERLACED)
37962306a36Sopenharmony_ci		malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
38062306a36Sopenharmony_ci	else
38162306a36Sopenharmony_ci		malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	/*
38462306a36Sopenharmony_ci	 * Program the RQoS register to avoid high resolutions flicker
38562306a36Sopenharmony_ci	 * issue on the LS1028A.
38662306a36Sopenharmony_ci	 */
38762306a36Sopenharmony_ci	if (hwdev->arqos_value) {
38862306a36Sopenharmony_ci		val = hwdev->arqos_value;
38962306a36Sopenharmony_ci		malidp_hw_setbits(hwdev, val, MALIDP500_RQOS_QUALITY);
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ciint malidp_format_get_bpp(u32 fmt)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	const struct drm_format_info *info = drm_format_info(fmt);
39662306a36Sopenharmony_ci	int bpp = info->cpp[0] * 8;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (bpp == 0) {
39962306a36Sopenharmony_ci		switch (fmt) {
40062306a36Sopenharmony_ci		case DRM_FORMAT_VUY101010:
40162306a36Sopenharmony_ci			bpp = 30;
40262306a36Sopenharmony_ci			break;
40362306a36Sopenharmony_ci		case DRM_FORMAT_YUV420_10BIT:
40462306a36Sopenharmony_ci			bpp = 15;
40562306a36Sopenharmony_ci			break;
40662306a36Sopenharmony_ci		case DRM_FORMAT_YUV420_8BIT:
40762306a36Sopenharmony_ci			bpp = 12;
40862306a36Sopenharmony_ci			break;
40962306a36Sopenharmony_ci		default:
41062306a36Sopenharmony_ci			bpp = 0;
41162306a36Sopenharmony_ci		}
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	return bpp;
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cistatic int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
41862306a36Sopenharmony_ci				     u16 h, u32 fmt, bool has_modifier)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	/*
42162306a36Sopenharmony_ci	 * Each layer needs enough rotation memory to fit 8 lines
42262306a36Sopenharmony_ci	 * worth of pixel data. Required size is then:
42362306a36Sopenharmony_ci	 *    size = rotated_width * (bpp / 8) * 8;
42462306a36Sopenharmony_ci	 */
42562306a36Sopenharmony_ci	int bpp = malidp_format_get_bpp(fmt);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	return w * bpp;
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
43162306a36Sopenharmony_ci					   u32 direction,
43262306a36Sopenharmony_ci					   u16 addr,
43362306a36Sopenharmony_ci					   u8 coeffs_id)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	int i;
43662306a36Sopenharmony_ci	u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	malidp_hw_write(hwdev,
43962306a36Sopenharmony_ci			direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK),
44062306a36Sopenharmony_ci			scaling_control + MALIDP_SE_COEFFTAB_ADDR);
44162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i)
44262306a36Sopenharmony_ci		malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA(
44362306a36Sopenharmony_ci				dp500_se_scaling_coeffs[coeffs_id][i]),
44462306a36Sopenharmony_ci				scaling_control + MALIDP_SE_COEFFTAB_DATA);
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
44862306a36Sopenharmony_ci					   struct malidp_se_config *se_config,
44962306a36Sopenharmony_ci					   struct malidp_se_config *old_config)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	/* Get array indices into dp500_se_scaling_coeffs. */
45262306a36Sopenharmony_ci	u8 h = (u8)se_config->hcoeff - 1;
45362306a36Sopenharmony_ci	u8 v = (u8)se_config->vcoeff - 1;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
45662306a36Sopenharmony_ci		    v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
45762306a36Sopenharmony_ci		return -EINVAL;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	if ((h == v) && (se_config->hcoeff != old_config->hcoeff ||
46062306a36Sopenharmony_ci			 se_config->vcoeff != old_config->vcoeff)) {
46162306a36Sopenharmony_ci		malidp500_se_write_pp_coefftab(hwdev,
46262306a36Sopenharmony_ci					       (MALIDP_SE_V_COEFFTAB |
46362306a36Sopenharmony_ci						MALIDP_SE_H_COEFFTAB),
46462306a36Sopenharmony_ci					       0, v);
46562306a36Sopenharmony_ci	} else {
46662306a36Sopenharmony_ci		if (se_config->vcoeff != old_config->vcoeff)
46762306a36Sopenharmony_ci			malidp500_se_write_pp_coefftab(hwdev,
46862306a36Sopenharmony_ci						       MALIDP_SE_V_COEFFTAB,
46962306a36Sopenharmony_ci						       0, v);
47062306a36Sopenharmony_ci		if (se_config->hcoeff != old_config->hcoeff)
47162306a36Sopenharmony_ci			malidp500_se_write_pp_coefftab(hwdev,
47262306a36Sopenharmony_ci						       MALIDP_SE_H_COEFFTAB,
47362306a36Sopenharmony_ci						       0, h);
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	return 0;
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_cistatic long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
48062306a36Sopenharmony_ci				   struct malidp_se_config *se_config,
48162306a36Sopenharmony_ci				   struct videomode *vm)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	unsigned long mclk;
48462306a36Sopenharmony_ci	unsigned long pxlclk = vm->pixelclock; /* Hz */
48562306a36Sopenharmony_ci	unsigned long htotal = vm->hactive + vm->hfront_porch +
48662306a36Sopenharmony_ci			       vm->hback_porch + vm->hsync_len;
48762306a36Sopenharmony_ci	unsigned long input_size = se_config->input_w * se_config->input_h;
48862306a36Sopenharmony_ci	unsigned long a = 10;
48962306a36Sopenharmony_ci	long ret;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	/*
49262306a36Sopenharmony_ci	 * mclk = max(a, 1.5) * pxlclk
49362306a36Sopenharmony_ci	 *
49462306a36Sopenharmony_ci	 * To avoid float calculaiton, using 15 instead of 1.5 and div by
49562306a36Sopenharmony_ci	 * 10 to get mclk.
49662306a36Sopenharmony_ci	 */
49762306a36Sopenharmony_ci	if (se_config->scale_enable) {
49862306a36Sopenharmony_ci		a = 15 * input_size / (htotal * se_config->output_h);
49962306a36Sopenharmony_ci		if (a < 15)
50062306a36Sopenharmony_ci			a = 15;
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci	mclk = a * pxlclk / 10;
50362306a36Sopenharmony_ci	ret = clk_get_rate(hwdev->mclk);
50462306a36Sopenharmony_ci	if (ret < mclk) {
50562306a36Sopenharmony_ci		DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
50662306a36Sopenharmony_ci				 mclk / 1000);
50762306a36Sopenharmony_ci		return -EINVAL;
50862306a36Sopenharmony_ci	}
50962306a36Sopenharmony_ci	return ret;
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cistatic int malidp500_enable_memwrite(struct malidp_hw_device *hwdev,
51362306a36Sopenharmony_ci				     dma_addr_t *addrs, s32 *pitches,
51462306a36Sopenharmony_ci				     int num_planes, u16 w, u16 h, u32 fmt_id,
51562306a36Sopenharmony_ci				     const s16 *rgb2yuv_coeffs)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	u32 base = MALIDP500_SE_MEMWRITE_BASE;
51862306a36Sopenharmony_ci	u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	/* enable the scaling engine block */
52162306a36Sopenharmony_ci	malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/* restart the writeback if already enabled */
52462306a36Sopenharmony_ci	if (hwdev->mw_state != MW_NOT_ENABLED)
52562306a36Sopenharmony_ci		hwdev->mw_state = MW_RESTART;
52662306a36Sopenharmony_ci	else
52762306a36Sopenharmony_ci		hwdev->mw_state = MW_START;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
53062306a36Sopenharmony_ci	switch (num_planes) {
53162306a36Sopenharmony_ci	case 2:
53262306a36Sopenharmony_ci		malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
53362306a36Sopenharmony_ci		malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
53462306a36Sopenharmony_ci		malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
53562306a36Sopenharmony_ci		fallthrough;
53662306a36Sopenharmony_ci	case 1:
53762306a36Sopenharmony_ci		malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
53862306a36Sopenharmony_ci		malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
53962306a36Sopenharmony_ci		malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
54062306a36Sopenharmony_ci		break;
54162306a36Sopenharmony_ci	default:
54262306a36Sopenharmony_ci		WARN(1, "Invalid number of planes");
54362306a36Sopenharmony_ci	}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
54662306a36Sopenharmony_ci			MALIDP500_SE_MEMWRITE_OUT_SIZE);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	if (rgb2yuv_coeffs) {
54962306a36Sopenharmony_ci		int i;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci		for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
55262306a36Sopenharmony_ci			malidp_hw_write(hwdev, rgb2yuv_coeffs[i],
55362306a36Sopenharmony_ci					MALIDP500_SE_RGB_YUV_COEFFS + i * 4);
55462306a36Sopenharmony_ci		}
55562306a36Sopenharmony_ci	}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	malidp_hw_setbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	return 0;
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_cistatic void malidp500_disable_memwrite(struct malidp_hw_device *hwdev)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	if (hwdev->mw_state == MW_START || hwdev->mw_state == MW_RESTART)
56762306a36Sopenharmony_ci		hwdev->mw_state = MW_STOP;
56862306a36Sopenharmony_ci	malidp_hw_clearbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
56962306a36Sopenharmony_ci	malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_cistatic int malidp550_query_hw(struct malidp_hw_device *hwdev)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
57562306a36Sopenharmony_ci	u8 ln_size = (conf >> 4) & 0x3, rsize;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	hwdev->min_line_size = 2;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	switch (ln_size) {
58062306a36Sopenharmony_ci	case 0:
58162306a36Sopenharmony_ci		hwdev->max_line_size = SZ_2K;
58262306a36Sopenharmony_ci		/* two banks of 64KB for rotation memory */
58362306a36Sopenharmony_ci		rsize = 64;
58462306a36Sopenharmony_ci		break;
58562306a36Sopenharmony_ci	case 1:
58662306a36Sopenharmony_ci		hwdev->max_line_size = SZ_4K;
58762306a36Sopenharmony_ci		/* two banks of 128KB for rotation memory */
58862306a36Sopenharmony_ci		rsize = 128;
58962306a36Sopenharmony_ci		break;
59062306a36Sopenharmony_ci	case 2:
59162306a36Sopenharmony_ci		hwdev->max_line_size = 1280;
59262306a36Sopenharmony_ci		/* two banks of 40KB for rotation memory */
59362306a36Sopenharmony_ci		rsize = 40;
59462306a36Sopenharmony_ci		break;
59562306a36Sopenharmony_ci	case 3:
59662306a36Sopenharmony_ci		/* reserved value */
59762306a36Sopenharmony_ci		hwdev->max_line_size = 0;
59862306a36Sopenharmony_ci		return -EINVAL;
59962306a36Sopenharmony_ci	}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
60262306a36Sopenharmony_ci	return 0;
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_cistatic void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	u32 status, count = 100;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
61062306a36Sopenharmony_ci	while (count) {
61162306a36Sopenharmony_ci		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
61262306a36Sopenharmony_ci		if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
61362306a36Sopenharmony_ci			break;
61462306a36Sopenharmony_ci		/*
61562306a36Sopenharmony_ci		 * entering config mode can take as long as the rendering
61662306a36Sopenharmony_ci		 * of a full frame, hence the long sleep here
61762306a36Sopenharmony_ci		 */
61862306a36Sopenharmony_ci		usleep_range(1000, 10000);
61962306a36Sopenharmony_ci		count--;
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci	WARN(count == 0, "timeout while entering config mode");
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cistatic void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	u32 status, count = 100;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
62962306a36Sopenharmony_ci	malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
63062306a36Sopenharmony_ci	while (count) {
63162306a36Sopenharmony_ci		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
63262306a36Sopenharmony_ci		if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
63362306a36Sopenharmony_ci			break;
63462306a36Sopenharmony_ci		usleep_range(100, 1000);
63562306a36Sopenharmony_ci		count--;
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ci	WARN(count == 0, "timeout while leaving config mode");
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_cistatic bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
64162306a36Sopenharmony_ci{
64262306a36Sopenharmony_ci	u32 status;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
64562306a36Sopenharmony_ci	if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
64662306a36Sopenharmony_ci		return true;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	return false;
64962306a36Sopenharmony_ci}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_cistatic void malidp550_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	if (value)
65462306a36Sopenharmony_ci		malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
65562306a36Sopenharmony_ci	else
65662306a36Sopenharmony_ci		malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cistatic void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
66062306a36Sopenharmony_ci{
66162306a36Sopenharmony_ci	u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	malidp_hw_write(hwdev, hwdev->output_color_depth,
66462306a36Sopenharmony_ci		hwdev->hw->map.out_depth_base);
66562306a36Sopenharmony_ci	malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
66662306a36Sopenharmony_ci	/*
66762306a36Sopenharmony_ci	 * Mali-DP550 and Mali-DP650 encode the background color like this:
66862306a36Sopenharmony_ci	 *   - red   @ MALIDP550_DE_BGND_COLOR[23:16]
66962306a36Sopenharmony_ci	 *   - green @ MALIDP550_DE_BGND_COLOR[15:8]
67062306a36Sopenharmony_ci	 *   - blue  @ MALIDP550_DE_BGND_COLOR[7:0]
67162306a36Sopenharmony_ci	 *
67262306a36Sopenharmony_ci	 * We need to truncate the least significant 4 bits from the default
67362306a36Sopenharmony_ci	 * MALIDP_BGND_COLOR_x values
67462306a36Sopenharmony_ci	 */
67562306a36Sopenharmony_ci	val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
67662306a36Sopenharmony_ci	      (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
67762306a36Sopenharmony_ci	      ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
67862306a36Sopenharmony_ci	malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
68162306a36Sopenharmony_ci		MALIDP_DE_H_BACKPORCH(mode->hback_porch);
68262306a36Sopenharmony_ci	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
68562306a36Sopenharmony_ci		MALIDP_DE_V_BACKPORCH(mode->vback_porch);
68662306a36Sopenharmony_ci	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
68962306a36Sopenharmony_ci		MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
69062306a36Sopenharmony_ci	if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
69162306a36Sopenharmony_ci		val |= MALIDP550_HSYNCPOL;
69262306a36Sopenharmony_ci	if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
69362306a36Sopenharmony_ci		val |= MALIDP550_VSYNCPOL;
69462306a36Sopenharmony_ci	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
69762306a36Sopenharmony_ci	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	if (mode->flags & DISPLAY_FLAGS_INTERLACED)
70062306a36Sopenharmony_ci		malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
70162306a36Sopenharmony_ci	else
70262306a36Sopenharmony_ci		malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
70362306a36Sopenharmony_ci}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_cistatic int malidpx50_get_bytes_per_column(u32 fmt)
70662306a36Sopenharmony_ci{
70762306a36Sopenharmony_ci	u32 bytes_per_column;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	switch (fmt) {
71062306a36Sopenharmony_ci	/* 8 lines at 4 bytes per pixel */
71162306a36Sopenharmony_ci	case DRM_FORMAT_ARGB2101010:
71262306a36Sopenharmony_ci	case DRM_FORMAT_ABGR2101010:
71362306a36Sopenharmony_ci	case DRM_FORMAT_RGBA1010102:
71462306a36Sopenharmony_ci	case DRM_FORMAT_BGRA1010102:
71562306a36Sopenharmony_ci	case DRM_FORMAT_ARGB8888:
71662306a36Sopenharmony_ci	case DRM_FORMAT_ABGR8888:
71762306a36Sopenharmony_ci	case DRM_FORMAT_RGBA8888:
71862306a36Sopenharmony_ci	case DRM_FORMAT_BGRA8888:
71962306a36Sopenharmony_ci	case DRM_FORMAT_XRGB8888:
72062306a36Sopenharmony_ci	case DRM_FORMAT_XBGR8888:
72162306a36Sopenharmony_ci	case DRM_FORMAT_RGBX8888:
72262306a36Sopenharmony_ci	case DRM_FORMAT_BGRX8888:
72362306a36Sopenharmony_ci	case DRM_FORMAT_RGB888:
72462306a36Sopenharmony_ci	case DRM_FORMAT_BGR888:
72562306a36Sopenharmony_ci	/* 16 lines at 2 bytes per pixel */
72662306a36Sopenharmony_ci	case DRM_FORMAT_RGBA5551:
72762306a36Sopenharmony_ci	case DRM_FORMAT_ABGR1555:
72862306a36Sopenharmony_ci	case DRM_FORMAT_RGB565:
72962306a36Sopenharmony_ci	case DRM_FORMAT_BGR565:
73062306a36Sopenharmony_ci	case DRM_FORMAT_UYVY:
73162306a36Sopenharmony_ci	case DRM_FORMAT_YUYV:
73262306a36Sopenharmony_ci	case DRM_FORMAT_X0L0:
73362306a36Sopenharmony_ci		bytes_per_column = 32;
73462306a36Sopenharmony_ci		break;
73562306a36Sopenharmony_ci	/* 16 lines at 1.5 bytes per pixel */
73662306a36Sopenharmony_ci	case DRM_FORMAT_NV12:
73762306a36Sopenharmony_ci	case DRM_FORMAT_YUV420:
73862306a36Sopenharmony_ci	/* 8 lines at 3 bytes per pixel */
73962306a36Sopenharmony_ci	case DRM_FORMAT_VUY888:
74062306a36Sopenharmony_ci	/* 16 lines at 12 bits per pixel */
74162306a36Sopenharmony_ci	case DRM_FORMAT_YUV420_8BIT:
74262306a36Sopenharmony_ci	/* 8 lines at 3 bytes per pixel */
74362306a36Sopenharmony_ci	case DRM_FORMAT_P010:
74462306a36Sopenharmony_ci		bytes_per_column = 24;
74562306a36Sopenharmony_ci		break;
74662306a36Sopenharmony_ci	/* 8 lines at 30 bits per pixel */
74762306a36Sopenharmony_ci	case DRM_FORMAT_VUY101010:
74862306a36Sopenharmony_ci	/* 16 lines at 15 bits per pixel */
74962306a36Sopenharmony_ci	case DRM_FORMAT_YUV420_10BIT:
75062306a36Sopenharmony_ci		bytes_per_column = 30;
75162306a36Sopenharmony_ci		break;
75262306a36Sopenharmony_ci	default:
75362306a36Sopenharmony_ci		return -EINVAL;
75462306a36Sopenharmony_ci	}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	return bytes_per_column;
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_cistatic int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
76062306a36Sopenharmony_ci				     u16 h, u32 fmt, bool has_modifier)
76162306a36Sopenharmony_ci{
76262306a36Sopenharmony_ci	int bytes_per_column = 0;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	switch (fmt) {
76562306a36Sopenharmony_ci	/* 8 lines at 15 bits per pixel */
76662306a36Sopenharmony_ci	case DRM_FORMAT_YUV420_10BIT:
76762306a36Sopenharmony_ci		bytes_per_column = 15;
76862306a36Sopenharmony_ci		break;
76962306a36Sopenharmony_ci	/* Uncompressed YUV 420 10 bit single plane cannot be rotated */
77062306a36Sopenharmony_ci	case DRM_FORMAT_X0L2:
77162306a36Sopenharmony_ci		if (has_modifier)
77262306a36Sopenharmony_ci			bytes_per_column = 8;
77362306a36Sopenharmony_ci		else
77462306a36Sopenharmony_ci			return -EINVAL;
77562306a36Sopenharmony_ci		break;
77662306a36Sopenharmony_ci	default:
77762306a36Sopenharmony_ci		bytes_per_column = malidpx50_get_bytes_per_column(fmt);
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	if (bytes_per_column == -EINVAL)
78162306a36Sopenharmony_ci		return bytes_per_column;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	return w * bytes_per_column;
78462306a36Sopenharmony_ci}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cistatic int malidp650_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
78762306a36Sopenharmony_ci				     u16 h, u32 fmt, bool has_modifier)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	int bytes_per_column = 0;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	switch (fmt) {
79262306a36Sopenharmony_ci	/* 16 lines at 2 bytes per pixel */
79362306a36Sopenharmony_ci	case DRM_FORMAT_X0L2:
79462306a36Sopenharmony_ci		bytes_per_column = 32;
79562306a36Sopenharmony_ci		break;
79662306a36Sopenharmony_ci	default:
79762306a36Sopenharmony_ci		bytes_per_column = malidpx50_get_bytes_per_column(fmt);
79862306a36Sopenharmony_ci	}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	if (bytes_per_column == -EINVAL)
80162306a36Sopenharmony_ci		return bytes_per_column;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	return w * bytes_per_column;
80462306a36Sopenharmony_ci}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_cistatic int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
80762306a36Sopenharmony_ci					   struct malidp_se_config *se_config,
80862306a36Sopenharmony_ci					   struct malidp_se_config *old_config)
80962306a36Sopenharmony_ci{
81062306a36Sopenharmony_ci	u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) |
81162306a36Sopenharmony_ci		   MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK);
81262306a36Sopenharmony_ci	u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) |
81362306a36Sopenharmony_ci			MALIDP550_SE_CTL_HCSEL(se_config->hcoeff);
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
81662306a36Sopenharmony_ci	malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
81762306a36Sopenharmony_ci	return 0;
81862306a36Sopenharmony_ci}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_cistatic long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
82162306a36Sopenharmony_ci				   struct malidp_se_config *se_config,
82262306a36Sopenharmony_ci				   struct videomode *vm)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	unsigned long mclk;
82562306a36Sopenharmony_ci	unsigned long pxlclk = vm->pixelclock;
82662306a36Sopenharmony_ci	unsigned long htotal = vm->hactive + vm->hfront_porch +
82762306a36Sopenharmony_ci			       vm->hback_porch + vm->hsync_len;
82862306a36Sopenharmony_ci	unsigned long numerator = 1, denominator = 1;
82962306a36Sopenharmony_ci	long ret;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	if (se_config->scale_enable) {
83262306a36Sopenharmony_ci		numerator = max(se_config->input_w, se_config->output_w) *
83362306a36Sopenharmony_ci			    se_config->input_h;
83462306a36Sopenharmony_ci		numerator += se_config->output_w *
83562306a36Sopenharmony_ci			     (se_config->output_h -
83662306a36Sopenharmony_ci			      min(se_config->input_h, se_config->output_h));
83762306a36Sopenharmony_ci		denominator = (htotal - 2) * se_config->output_h;
83862306a36Sopenharmony_ci	}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	/* mclk can't be slower than pxlclk. */
84162306a36Sopenharmony_ci	if (numerator < denominator)
84262306a36Sopenharmony_ci		numerator = denominator = 1;
84362306a36Sopenharmony_ci	mclk = (pxlclk * numerator) / denominator;
84462306a36Sopenharmony_ci	ret = clk_get_rate(hwdev->mclk);
84562306a36Sopenharmony_ci	if (ret < mclk) {
84662306a36Sopenharmony_ci		DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
84762306a36Sopenharmony_ci				 mclk / 1000);
84862306a36Sopenharmony_ci		return -EINVAL;
84962306a36Sopenharmony_ci	}
85062306a36Sopenharmony_ci	return ret;
85162306a36Sopenharmony_ci}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_cistatic int malidp550_enable_memwrite(struct malidp_hw_device *hwdev,
85462306a36Sopenharmony_ci				     dma_addr_t *addrs, s32 *pitches,
85562306a36Sopenharmony_ci				     int num_planes, u16 w, u16 h, u32 fmt_id,
85662306a36Sopenharmony_ci				     const s16 *rgb2yuv_coeffs)
85762306a36Sopenharmony_ci{
85862306a36Sopenharmony_ci	u32 base = MALIDP550_SE_MEMWRITE_BASE;
85962306a36Sopenharmony_ci	u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	/* enable the scaling engine block */
86262306a36Sopenharmony_ci	malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	hwdev->mw_state = MW_ONESHOT;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
86762306a36Sopenharmony_ci	switch (num_planes) {
86862306a36Sopenharmony_ci	case 2:
86962306a36Sopenharmony_ci		malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
87062306a36Sopenharmony_ci		malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
87162306a36Sopenharmony_ci		malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
87262306a36Sopenharmony_ci		fallthrough;
87362306a36Sopenharmony_ci	case 1:
87462306a36Sopenharmony_ci		malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
87562306a36Sopenharmony_ci		malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
87662306a36Sopenharmony_ci		malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
87762306a36Sopenharmony_ci		break;
87862306a36Sopenharmony_ci	default:
87962306a36Sopenharmony_ci		WARN(1, "Invalid number of planes");
88062306a36Sopenharmony_ci	}
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
88362306a36Sopenharmony_ci			MALIDP550_SE_MEMWRITE_OUT_SIZE);
88462306a36Sopenharmony_ci	malidp_hw_setbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
88562306a36Sopenharmony_ci			  MALIDP550_SE_CONTROL);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	if (rgb2yuv_coeffs) {
88862306a36Sopenharmony_ci		int i;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci		for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
89162306a36Sopenharmony_ci			malidp_hw_write(hwdev, rgb2yuv_coeffs[i],
89262306a36Sopenharmony_ci					MALIDP550_SE_RGB_YUV_COEFFS + i * 4);
89362306a36Sopenharmony_ci		}
89462306a36Sopenharmony_ci	}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	return 0;
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_cistatic void malidp550_disable_memwrite(struct malidp_hw_device *hwdev)
90062306a36Sopenharmony_ci{
90162306a36Sopenharmony_ci	u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	malidp_hw_clearbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
90462306a36Sopenharmony_ci			    MALIDP550_SE_CONTROL);
90562306a36Sopenharmony_ci	malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
90662306a36Sopenharmony_ci}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_cistatic int malidp650_query_hw(struct malidp_hw_device *hwdev)
90962306a36Sopenharmony_ci{
91062306a36Sopenharmony_ci	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
91162306a36Sopenharmony_ci	u8 ln_size = (conf >> 4) & 0x3, rsize;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	hwdev->min_line_size = 4;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	switch (ln_size) {
91662306a36Sopenharmony_ci	case 0:
91762306a36Sopenharmony_ci	case 2:
91862306a36Sopenharmony_ci		/* reserved values */
91962306a36Sopenharmony_ci		hwdev->max_line_size = 0;
92062306a36Sopenharmony_ci		return -EINVAL;
92162306a36Sopenharmony_ci	case 1:
92262306a36Sopenharmony_ci		hwdev->max_line_size = SZ_4K;
92362306a36Sopenharmony_ci		/* two banks of 128KB for rotation memory */
92462306a36Sopenharmony_ci		rsize = 128;
92562306a36Sopenharmony_ci		break;
92662306a36Sopenharmony_ci	case 3:
92762306a36Sopenharmony_ci		hwdev->max_line_size = 2560;
92862306a36Sopenharmony_ci		/* two banks of 80KB for rotation memory */
92962306a36Sopenharmony_ci		rsize = 80;
93062306a36Sopenharmony_ci	}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
93362306a36Sopenharmony_ci	return 0;
93462306a36Sopenharmony_ci}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ciconst struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
93762306a36Sopenharmony_ci	[MALIDP_500] = {
93862306a36Sopenharmony_ci		.map = {
93962306a36Sopenharmony_ci			.coeffs_base = MALIDP500_COEFFS_BASE,
94062306a36Sopenharmony_ci			.se_base = MALIDP500_SE_BASE,
94162306a36Sopenharmony_ci			.dc_base = MALIDP500_DC_BASE,
94262306a36Sopenharmony_ci			.out_depth_base = MALIDP500_OUTPUT_DEPTH,
94362306a36Sopenharmony_ci			.features = 0,	/* no CLEARIRQ register */
94462306a36Sopenharmony_ci			.n_layers = ARRAY_SIZE(malidp500_layers),
94562306a36Sopenharmony_ci			.layers = malidp500_layers,
94662306a36Sopenharmony_ci			.de_irq_map = {
94762306a36Sopenharmony_ci				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
94862306a36Sopenharmony_ci					    MALIDP500_DE_IRQ_AXI_ERR |
94962306a36Sopenharmony_ci					    MALIDP500_DE_IRQ_VSYNC |
95062306a36Sopenharmony_ci					    MALIDP500_DE_IRQ_GLOBAL,
95162306a36Sopenharmony_ci				.vsync_irq = MALIDP500_DE_IRQ_VSYNC,
95262306a36Sopenharmony_ci				.err_mask = MALIDP_DE_IRQ_UNDERRUN |
95362306a36Sopenharmony_ci					    MALIDP500_DE_IRQ_AXI_ERR |
95462306a36Sopenharmony_ci					    MALIDP500_DE_IRQ_SATURATION,
95562306a36Sopenharmony_ci			},
95662306a36Sopenharmony_ci			.se_irq_map = {
95762306a36Sopenharmony_ci				.irq_mask = MALIDP500_SE_IRQ_CONF_MODE |
95862306a36Sopenharmony_ci					    MALIDP500_SE_IRQ_CONF_VALID |
95962306a36Sopenharmony_ci					    MALIDP500_SE_IRQ_GLOBAL,
96062306a36Sopenharmony_ci				.vsync_irq = MALIDP500_SE_IRQ_CONF_VALID,
96162306a36Sopenharmony_ci				.err_mask = MALIDP500_SE_IRQ_INIT_BUSY |
96262306a36Sopenharmony_ci					    MALIDP500_SE_IRQ_AXI_ERROR |
96362306a36Sopenharmony_ci					    MALIDP500_SE_IRQ_OVERRUN,
96462306a36Sopenharmony_ci			},
96562306a36Sopenharmony_ci			.dc_irq_map = {
96662306a36Sopenharmony_ci				.irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
96762306a36Sopenharmony_ci				.vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
96862306a36Sopenharmony_ci			},
96962306a36Sopenharmony_ci			.pixel_formats = malidp500_de_formats,
97062306a36Sopenharmony_ci			.n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
97162306a36Sopenharmony_ci			.bus_align_bytes = 8,
97262306a36Sopenharmony_ci		},
97362306a36Sopenharmony_ci		.query_hw = malidp500_query_hw,
97462306a36Sopenharmony_ci		.enter_config_mode = malidp500_enter_config_mode,
97562306a36Sopenharmony_ci		.leave_config_mode = malidp500_leave_config_mode,
97662306a36Sopenharmony_ci		.in_config_mode = malidp500_in_config_mode,
97762306a36Sopenharmony_ci		.set_config_valid = malidp500_set_config_valid,
97862306a36Sopenharmony_ci		.modeset = malidp500_modeset,
97962306a36Sopenharmony_ci		.rotmem_required = malidp500_rotmem_required,
98062306a36Sopenharmony_ci		.se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
98162306a36Sopenharmony_ci		.se_calc_mclk = malidp500_se_calc_mclk,
98262306a36Sopenharmony_ci		.enable_memwrite = malidp500_enable_memwrite,
98362306a36Sopenharmony_ci		.disable_memwrite = malidp500_disable_memwrite,
98462306a36Sopenharmony_ci		.features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
98562306a36Sopenharmony_ci	},
98662306a36Sopenharmony_ci	[MALIDP_550] = {
98762306a36Sopenharmony_ci		.map = {
98862306a36Sopenharmony_ci			.coeffs_base = MALIDP550_COEFFS_BASE,
98962306a36Sopenharmony_ci			.se_base = MALIDP550_SE_BASE,
99062306a36Sopenharmony_ci			.dc_base = MALIDP550_DC_BASE,
99162306a36Sopenharmony_ci			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
99262306a36Sopenharmony_ci			.features = MALIDP_REGMAP_HAS_CLEARIRQ |
99362306a36Sopenharmony_ci				    MALIDP_DEVICE_AFBC_SUPPORT_SPLIT |
99462306a36Sopenharmony_ci				    MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT |
99562306a36Sopenharmony_ci				    MALIDP_DEVICE_AFBC_YUYV_USE_422_P2,
99662306a36Sopenharmony_ci			.n_layers = ARRAY_SIZE(malidp550_layers),
99762306a36Sopenharmony_ci			.layers = malidp550_layers,
99862306a36Sopenharmony_ci			.de_irq_map = {
99962306a36Sopenharmony_ci				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
100062306a36Sopenharmony_ci					    MALIDP550_DE_IRQ_VSYNC,
100162306a36Sopenharmony_ci				.vsync_irq = MALIDP550_DE_IRQ_VSYNC,
100262306a36Sopenharmony_ci				.err_mask = MALIDP_DE_IRQ_UNDERRUN |
100362306a36Sopenharmony_ci					    MALIDP550_DE_IRQ_SATURATION |
100462306a36Sopenharmony_ci					    MALIDP550_DE_IRQ_AXI_ERR,
100562306a36Sopenharmony_ci			},
100662306a36Sopenharmony_ci			.se_irq_map = {
100762306a36Sopenharmony_ci				.irq_mask = MALIDP550_SE_IRQ_EOW,
100862306a36Sopenharmony_ci				.vsync_irq = MALIDP550_SE_IRQ_EOW,
100962306a36Sopenharmony_ci				.err_mask  = MALIDP550_SE_IRQ_AXI_ERR |
101062306a36Sopenharmony_ci					     MALIDP550_SE_IRQ_OVR |
101162306a36Sopenharmony_ci					     MALIDP550_SE_IRQ_IBSY,
101262306a36Sopenharmony_ci			},
101362306a36Sopenharmony_ci			.dc_irq_map = {
101462306a36Sopenharmony_ci				.irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
101562306a36Sopenharmony_ci					    MALIDP550_DC_IRQ_SE,
101662306a36Sopenharmony_ci				.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
101762306a36Sopenharmony_ci			},
101862306a36Sopenharmony_ci			.pixel_formats = malidp550_de_formats,
101962306a36Sopenharmony_ci			.n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
102062306a36Sopenharmony_ci			.bus_align_bytes = 8,
102162306a36Sopenharmony_ci		},
102262306a36Sopenharmony_ci		.query_hw = malidp550_query_hw,
102362306a36Sopenharmony_ci		.enter_config_mode = malidp550_enter_config_mode,
102462306a36Sopenharmony_ci		.leave_config_mode = malidp550_leave_config_mode,
102562306a36Sopenharmony_ci		.in_config_mode = malidp550_in_config_mode,
102662306a36Sopenharmony_ci		.set_config_valid = malidp550_set_config_valid,
102762306a36Sopenharmony_ci		.modeset = malidp550_modeset,
102862306a36Sopenharmony_ci		.rotmem_required = malidp550_rotmem_required,
102962306a36Sopenharmony_ci		.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
103062306a36Sopenharmony_ci		.se_calc_mclk = malidp550_se_calc_mclk,
103162306a36Sopenharmony_ci		.enable_memwrite = malidp550_enable_memwrite,
103262306a36Sopenharmony_ci		.disable_memwrite = malidp550_disable_memwrite,
103362306a36Sopenharmony_ci		.features = 0,
103462306a36Sopenharmony_ci	},
103562306a36Sopenharmony_ci	[MALIDP_650] = {
103662306a36Sopenharmony_ci		.map = {
103762306a36Sopenharmony_ci			.coeffs_base = MALIDP550_COEFFS_BASE,
103862306a36Sopenharmony_ci			.se_base = MALIDP550_SE_BASE,
103962306a36Sopenharmony_ci			.dc_base = MALIDP550_DC_BASE,
104062306a36Sopenharmony_ci			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
104162306a36Sopenharmony_ci			.features = MALIDP_REGMAP_HAS_CLEARIRQ |
104262306a36Sopenharmony_ci				    MALIDP_DEVICE_AFBC_SUPPORT_SPLIT |
104362306a36Sopenharmony_ci				    MALIDP_DEVICE_AFBC_YUYV_USE_422_P2,
104462306a36Sopenharmony_ci			.n_layers = ARRAY_SIZE(malidp650_layers),
104562306a36Sopenharmony_ci			.layers = malidp650_layers,
104662306a36Sopenharmony_ci			.de_irq_map = {
104762306a36Sopenharmony_ci				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
104862306a36Sopenharmony_ci					    MALIDP650_DE_IRQ_DRIFT |
104962306a36Sopenharmony_ci					    MALIDP550_DE_IRQ_VSYNC,
105062306a36Sopenharmony_ci				.vsync_irq = MALIDP550_DE_IRQ_VSYNC,
105162306a36Sopenharmony_ci				.err_mask = MALIDP_DE_IRQ_UNDERRUN |
105262306a36Sopenharmony_ci					    MALIDP650_DE_IRQ_DRIFT |
105362306a36Sopenharmony_ci					    MALIDP550_DE_IRQ_SATURATION |
105462306a36Sopenharmony_ci					    MALIDP550_DE_IRQ_AXI_ERR |
105562306a36Sopenharmony_ci					    MALIDP650_DE_IRQ_ACEV1 |
105662306a36Sopenharmony_ci					    MALIDP650_DE_IRQ_ACEV2 |
105762306a36Sopenharmony_ci					    MALIDP650_DE_IRQ_ACEG |
105862306a36Sopenharmony_ci					    MALIDP650_DE_IRQ_AXIEP,
105962306a36Sopenharmony_ci			},
106062306a36Sopenharmony_ci			.se_irq_map = {
106162306a36Sopenharmony_ci				.irq_mask = MALIDP550_SE_IRQ_EOW,
106262306a36Sopenharmony_ci				.vsync_irq = MALIDP550_SE_IRQ_EOW,
106362306a36Sopenharmony_ci				.err_mask = MALIDP550_SE_IRQ_AXI_ERR |
106462306a36Sopenharmony_ci					    MALIDP550_SE_IRQ_OVR |
106562306a36Sopenharmony_ci					    MALIDP550_SE_IRQ_IBSY,
106662306a36Sopenharmony_ci			},
106762306a36Sopenharmony_ci			.dc_irq_map = {
106862306a36Sopenharmony_ci				.irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
106962306a36Sopenharmony_ci					    MALIDP550_DC_IRQ_SE,
107062306a36Sopenharmony_ci				.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
107162306a36Sopenharmony_ci			},
107262306a36Sopenharmony_ci			.pixel_formats = malidp650_de_formats,
107362306a36Sopenharmony_ci			.n_pixel_formats = ARRAY_SIZE(malidp650_de_formats),
107462306a36Sopenharmony_ci			.bus_align_bytes = 16,
107562306a36Sopenharmony_ci		},
107662306a36Sopenharmony_ci		.query_hw = malidp650_query_hw,
107762306a36Sopenharmony_ci		.enter_config_mode = malidp550_enter_config_mode,
107862306a36Sopenharmony_ci		.leave_config_mode = malidp550_leave_config_mode,
107962306a36Sopenharmony_ci		.in_config_mode = malidp550_in_config_mode,
108062306a36Sopenharmony_ci		.set_config_valid = malidp550_set_config_valid,
108162306a36Sopenharmony_ci		.modeset = malidp550_modeset,
108262306a36Sopenharmony_ci		.rotmem_required = malidp650_rotmem_required,
108362306a36Sopenharmony_ci		.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
108462306a36Sopenharmony_ci		.se_calc_mclk = malidp550_se_calc_mclk,
108562306a36Sopenharmony_ci		.enable_memwrite = malidp550_enable_memwrite,
108662306a36Sopenharmony_ci		.disable_memwrite = malidp550_disable_memwrite,
108762306a36Sopenharmony_ci		.features = 0,
108862306a36Sopenharmony_ci	},
108962306a36Sopenharmony_ci};
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ciu8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
109262306a36Sopenharmony_ci			   u8 layer_id, u32 format, bool has_modifier)
109362306a36Sopenharmony_ci{
109462306a36Sopenharmony_ci	unsigned int i;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	for (i = 0; i < map->n_pixel_formats; i++) {
109762306a36Sopenharmony_ci		if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
109862306a36Sopenharmony_ci		    (map->pixel_formats[i].format == format)) {
109962306a36Sopenharmony_ci			/*
110062306a36Sopenharmony_ci			 * In some DP550 and DP650, DRM_FORMAT_YUYV + AFBC modifier
110162306a36Sopenharmony_ci			 * is supported by a different h/w format id than
110262306a36Sopenharmony_ci			 * DRM_FORMAT_YUYV (only).
110362306a36Sopenharmony_ci			 */
110462306a36Sopenharmony_ci			if (format == DRM_FORMAT_YUYV &&
110562306a36Sopenharmony_ci			    (has_modifier) &&
110662306a36Sopenharmony_ci			    (map->features & MALIDP_DEVICE_AFBC_YUYV_USE_422_P2))
110762306a36Sopenharmony_ci				return AFBC_YUV_422_FORMAT_ID;
110862306a36Sopenharmony_ci			else
110962306a36Sopenharmony_ci				return map->pixel_formats[i].id;
111062306a36Sopenharmony_ci		}
111162306a36Sopenharmony_ci	}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	return MALIDP_INVALID_FORMAT_ID;
111462306a36Sopenharmony_ci}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_cibool malidp_hw_format_is_linear_only(u32 format)
111762306a36Sopenharmony_ci{
111862306a36Sopenharmony_ci	switch (format) {
111962306a36Sopenharmony_ci	case DRM_FORMAT_ARGB2101010:
112062306a36Sopenharmony_ci	case DRM_FORMAT_RGBA1010102:
112162306a36Sopenharmony_ci	case DRM_FORMAT_BGRA1010102:
112262306a36Sopenharmony_ci	case DRM_FORMAT_ARGB8888:
112362306a36Sopenharmony_ci	case DRM_FORMAT_RGBA8888:
112462306a36Sopenharmony_ci	case DRM_FORMAT_BGRA8888:
112562306a36Sopenharmony_ci	case DRM_FORMAT_XBGR8888:
112662306a36Sopenharmony_ci	case DRM_FORMAT_XRGB8888:
112762306a36Sopenharmony_ci	case DRM_FORMAT_RGBX8888:
112862306a36Sopenharmony_ci	case DRM_FORMAT_BGRX8888:
112962306a36Sopenharmony_ci	case DRM_FORMAT_RGB888:
113062306a36Sopenharmony_ci	case DRM_FORMAT_RGB565:
113162306a36Sopenharmony_ci	case DRM_FORMAT_ARGB1555:
113262306a36Sopenharmony_ci	case DRM_FORMAT_RGBA5551:
113362306a36Sopenharmony_ci	case DRM_FORMAT_BGRA5551:
113462306a36Sopenharmony_ci	case DRM_FORMAT_UYVY:
113562306a36Sopenharmony_ci	case DRM_FORMAT_XYUV8888:
113662306a36Sopenharmony_ci	case DRM_FORMAT_XVYU2101010:
113762306a36Sopenharmony_ci	case DRM_FORMAT_X0L2:
113862306a36Sopenharmony_ci	case DRM_FORMAT_X0L0:
113962306a36Sopenharmony_ci		return true;
114062306a36Sopenharmony_ci	default:
114162306a36Sopenharmony_ci		return false;
114262306a36Sopenharmony_ci	}
114362306a36Sopenharmony_ci}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_cibool malidp_hw_format_is_afbc_only(u32 format)
114662306a36Sopenharmony_ci{
114762306a36Sopenharmony_ci	switch (format) {
114862306a36Sopenharmony_ci	case DRM_FORMAT_VUY888:
114962306a36Sopenharmony_ci	case DRM_FORMAT_VUY101010:
115062306a36Sopenharmony_ci	case DRM_FORMAT_YUV420_8BIT:
115162306a36Sopenharmony_ci	case DRM_FORMAT_YUV420_10BIT:
115262306a36Sopenharmony_ci		return true;
115362306a36Sopenharmony_ci	default:
115462306a36Sopenharmony_ci		return false;
115562306a36Sopenharmony_ci	}
115662306a36Sopenharmony_ci}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_cistatic void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
115962306a36Sopenharmony_ci{
116062306a36Sopenharmony_ci	u32 base = malidp_get_block_base(hwdev, block);
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
116362306a36Sopenharmony_ci		malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
116462306a36Sopenharmony_ci	else
116562306a36Sopenharmony_ci		malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
116662306a36Sopenharmony_ci}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_cistatic irqreturn_t malidp_de_irq(int irq, void *arg)
116962306a36Sopenharmony_ci{
117062306a36Sopenharmony_ci	struct drm_device *drm = arg;
117162306a36Sopenharmony_ci	struct malidp_drm *malidp = drm_to_malidp(drm);
117262306a36Sopenharmony_ci	struct malidp_hw_device *hwdev;
117362306a36Sopenharmony_ci	struct malidp_hw *hw;
117462306a36Sopenharmony_ci	const struct malidp_irq_map *de;
117562306a36Sopenharmony_ci	u32 status, mask, dc_status;
117662306a36Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	hwdev = malidp->dev;
117962306a36Sopenharmony_ci	hw = hwdev->hw;
118062306a36Sopenharmony_ci	de = &hw->map.de_irq_map;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	/*
118362306a36Sopenharmony_ci	 * if we are suspended it is likely that we were invoked because
118462306a36Sopenharmony_ci	 * we share an interrupt line with some other driver, don't try
118562306a36Sopenharmony_ci	 * to read the hardware registers
118662306a36Sopenharmony_ci	 */
118762306a36Sopenharmony_ci	if (hwdev->pm_suspended)
118862306a36Sopenharmony_ci		return IRQ_NONE;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	/* first handle the config valid IRQ */
119162306a36Sopenharmony_ci	dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
119262306a36Sopenharmony_ci	if (dc_status & hw->map.dc_irq_map.vsync_irq) {
119362306a36Sopenharmony_ci		malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
119462306a36Sopenharmony_ci		/* do we have a page flip event? */
119562306a36Sopenharmony_ci		if (malidp->event != NULL) {
119662306a36Sopenharmony_ci			spin_lock(&drm->event_lock);
119762306a36Sopenharmony_ci			drm_crtc_send_vblank_event(&malidp->crtc, malidp->event);
119862306a36Sopenharmony_ci			malidp->event = NULL;
119962306a36Sopenharmony_ci			spin_unlock(&drm->event_lock);
120062306a36Sopenharmony_ci		}
120162306a36Sopenharmony_ci		atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE);
120262306a36Sopenharmony_ci		ret = IRQ_WAKE_THREAD;
120362306a36Sopenharmony_ci	}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
120662306a36Sopenharmony_ci	if (!(status & de->irq_mask))
120762306a36Sopenharmony_ci		return ret;
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
121062306a36Sopenharmony_ci	/* keep the status of the enabled interrupts, plus the error bits */
121162306a36Sopenharmony_ci	status &= (mask | de->err_mask);
121262306a36Sopenharmony_ci	if ((status & de->vsync_irq) && malidp->crtc.enabled)
121362306a36Sopenharmony_ci		drm_crtc_handle_vblank(&malidp->crtc);
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
121662306a36Sopenharmony_ci	if (status & de->err_mask) {
121762306a36Sopenharmony_ci		malidp_error(malidp, &malidp->de_errors, status,
121862306a36Sopenharmony_ci			     drm_crtc_vblank_count(&malidp->crtc));
121962306a36Sopenharmony_ci	}
122062306a36Sopenharmony_ci#endif
122162306a36Sopenharmony_ci	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
122462306a36Sopenharmony_ci}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_cistatic irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
122762306a36Sopenharmony_ci{
122862306a36Sopenharmony_ci	struct drm_device *drm = arg;
122962306a36Sopenharmony_ci	struct malidp_drm *malidp = drm_to_malidp(drm);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	wake_up(&malidp->wq);
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	return IRQ_HANDLED;
123462306a36Sopenharmony_ci}
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_civoid malidp_de_irq_hw_init(struct malidp_hw_device *hwdev)
123762306a36Sopenharmony_ci{
123862306a36Sopenharmony_ci	/* ensure interrupts are disabled */
123962306a36Sopenharmony_ci	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
124062306a36Sopenharmony_ci	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
124162306a36Sopenharmony_ci	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
124262306a36Sopenharmony_ci	malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	/* first enable the DC block IRQs */
124562306a36Sopenharmony_ci	malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
124662306a36Sopenharmony_ci			     hwdev->hw->map.dc_irq_map.irq_mask);
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	/* now enable the DE block IRQs */
124962306a36Sopenharmony_ci	malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
125062306a36Sopenharmony_ci			     hwdev->hw->map.de_irq_map.irq_mask);
125162306a36Sopenharmony_ci}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ciint malidp_de_irq_init(struct drm_device *drm, int irq)
125462306a36Sopenharmony_ci{
125562306a36Sopenharmony_ci	struct malidp_drm *malidp = drm_to_malidp(drm);
125662306a36Sopenharmony_ci	struct malidp_hw_device *hwdev = malidp->dev;
125762306a36Sopenharmony_ci	int ret;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	/* ensure interrupts are disabled */
126062306a36Sopenharmony_ci	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
126162306a36Sopenharmony_ci	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
126262306a36Sopenharmony_ci	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
126362306a36Sopenharmony_ci	malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
126662306a36Sopenharmony_ci					malidp_de_irq_thread_handler,
126762306a36Sopenharmony_ci					IRQF_SHARED, "malidp-de", drm);
126862306a36Sopenharmony_ci	if (ret < 0) {
126962306a36Sopenharmony_ci		DRM_ERROR("failed to install DE IRQ handler\n");
127062306a36Sopenharmony_ci		return ret;
127162306a36Sopenharmony_ci	}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	malidp_de_irq_hw_init(hwdev);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	return 0;
127662306a36Sopenharmony_ci}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_civoid malidp_de_irq_fini(struct malidp_hw_device *hwdev)
127962306a36Sopenharmony_ci{
128062306a36Sopenharmony_ci	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
128162306a36Sopenharmony_ci			      hwdev->hw->map.de_irq_map.irq_mask);
128262306a36Sopenharmony_ci	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
128362306a36Sopenharmony_ci			      hwdev->hw->map.dc_irq_map.irq_mask);
128462306a36Sopenharmony_ci}
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_cistatic irqreturn_t malidp_se_irq(int irq, void *arg)
128762306a36Sopenharmony_ci{
128862306a36Sopenharmony_ci	struct drm_device *drm = arg;
128962306a36Sopenharmony_ci	struct malidp_drm *malidp = drm_to_malidp(drm);
129062306a36Sopenharmony_ci	struct malidp_hw_device *hwdev = malidp->dev;
129162306a36Sopenharmony_ci	struct malidp_hw *hw = hwdev->hw;
129262306a36Sopenharmony_ci	const struct malidp_irq_map *se = &hw->map.se_irq_map;
129362306a36Sopenharmony_ci	u32 status, mask;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	/*
129662306a36Sopenharmony_ci	 * if we are suspended it is likely that we were invoked because
129762306a36Sopenharmony_ci	 * we share an interrupt line with some other driver, don't try
129862306a36Sopenharmony_ci	 * to read the hardware registers
129962306a36Sopenharmony_ci	 */
130062306a36Sopenharmony_ci	if (hwdev->pm_suspended)
130162306a36Sopenharmony_ci		return IRQ_NONE;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
130462306a36Sopenharmony_ci	if (!(status & (se->irq_mask | se->err_mask)))
130562306a36Sopenharmony_ci		return IRQ_NONE;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
130862306a36Sopenharmony_ci	if (status & se->err_mask)
130962306a36Sopenharmony_ci		malidp_error(malidp, &malidp->se_errors, status,
131062306a36Sopenharmony_ci			     drm_crtc_vblank_count(&malidp->crtc));
131162306a36Sopenharmony_ci#endif
131262306a36Sopenharmony_ci	mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ);
131362306a36Sopenharmony_ci	status &= mask;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	if (status & se->vsync_irq) {
131662306a36Sopenharmony_ci		switch (hwdev->mw_state) {
131762306a36Sopenharmony_ci		case MW_ONESHOT:
131862306a36Sopenharmony_ci			drm_writeback_signal_completion(&malidp->mw_connector, 0);
131962306a36Sopenharmony_ci			break;
132062306a36Sopenharmony_ci		case MW_STOP:
132162306a36Sopenharmony_ci			drm_writeback_signal_completion(&malidp->mw_connector, 0);
132262306a36Sopenharmony_ci			/* disable writeback after stop */
132362306a36Sopenharmony_ci			hwdev->mw_state = MW_NOT_ENABLED;
132462306a36Sopenharmony_ci			break;
132562306a36Sopenharmony_ci		case MW_RESTART:
132662306a36Sopenharmony_ci			drm_writeback_signal_completion(&malidp->mw_connector, 0);
132762306a36Sopenharmony_ci			fallthrough;	/* to a new start */
132862306a36Sopenharmony_ci		case MW_START:
132962306a36Sopenharmony_ci			/* writeback started, need to emulate one-shot mode */
133062306a36Sopenharmony_ci			hw->disable_memwrite(hwdev);
133162306a36Sopenharmony_ci			/*
133262306a36Sopenharmony_ci			 * only set config_valid HW bit if there is no other update
133362306a36Sopenharmony_ci			 * in progress or if we raced ahead of the DE IRQ handler
133462306a36Sopenharmony_ci			 * and config_valid flag will not be update until later
133562306a36Sopenharmony_ci			 */
133662306a36Sopenharmony_ci			status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
133762306a36Sopenharmony_ci			if ((atomic_read(&malidp->config_valid) != MALIDP_CONFIG_START) ||
133862306a36Sopenharmony_ci			    (status & hw->map.dc_irq_map.vsync_irq))
133962306a36Sopenharmony_ci				hw->set_config_valid(hwdev, 1);
134062306a36Sopenharmony_ci			break;
134162306a36Sopenharmony_ci		}
134262306a36Sopenharmony_ci	}
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	return IRQ_HANDLED;
134762306a36Sopenharmony_ci}
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_civoid malidp_se_irq_hw_init(struct malidp_hw_device *hwdev)
135062306a36Sopenharmony_ci{
135162306a36Sopenharmony_ci	/* ensure interrupts are disabled */
135262306a36Sopenharmony_ci	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
135362306a36Sopenharmony_ci	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
135662306a36Sopenharmony_ci			     hwdev->hw->map.se_irq_map.irq_mask);
135762306a36Sopenharmony_ci}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_cistatic irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
136062306a36Sopenharmony_ci{
136162306a36Sopenharmony_ci	return IRQ_HANDLED;
136262306a36Sopenharmony_ci}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ciint malidp_se_irq_init(struct drm_device *drm, int irq)
136562306a36Sopenharmony_ci{
136662306a36Sopenharmony_ci	struct malidp_drm *malidp = drm_to_malidp(drm);
136762306a36Sopenharmony_ci	struct malidp_hw_device *hwdev = malidp->dev;
136862306a36Sopenharmony_ci	int ret;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	/* ensure interrupts are disabled */
137162306a36Sopenharmony_ci	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
137262306a36Sopenharmony_ci	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
137562306a36Sopenharmony_ci					malidp_se_irq_thread_handler,
137662306a36Sopenharmony_ci					IRQF_SHARED, "malidp-se", drm);
137762306a36Sopenharmony_ci	if (ret < 0) {
137862306a36Sopenharmony_ci		DRM_ERROR("failed to install SE IRQ handler\n");
137962306a36Sopenharmony_ci		return ret;
138062306a36Sopenharmony_ci	}
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	hwdev->mw_state = MW_NOT_ENABLED;
138362306a36Sopenharmony_ci	malidp_se_irq_hw_init(hwdev);
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	return 0;
138662306a36Sopenharmony_ci}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_civoid malidp_se_irq_fini(struct malidp_hw_device *hwdev)
138962306a36Sopenharmony_ci{
139062306a36Sopenharmony_ci	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
139162306a36Sopenharmony_ci			      hwdev->hw->map.se_irq_map.irq_mask);
139262306a36Sopenharmony_ci}
1393