xref: /openbmc/linux/drivers/gpu/drm/arm/malidp_hw.c (revision 846c87a0)
1ad49f860SLiviu Dudau /*
2ad49f860SLiviu Dudau  * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
3ad49f860SLiviu Dudau  * Author: Liviu Dudau <Liviu.Dudau@arm.com>
4ad49f860SLiviu Dudau  *
5ad49f860SLiviu Dudau  * This program is free software and is provided to you under the terms of the
6ad49f860SLiviu Dudau  * GNU General Public License version 2 as published by the Free Software
7ad49f860SLiviu Dudau  * Foundation, and any use by you of this program is subject to the terms
8ad49f860SLiviu Dudau  * of such GNU licence.
9ad49f860SLiviu Dudau  *
10ad49f860SLiviu Dudau  * ARM Mali DP500/DP550/DP650 hardware manipulation routines. This is where
11ad49f860SLiviu Dudau  * the difference between various versions of the hardware is being dealt with
12ad49f860SLiviu Dudau  * in an attempt to provide to the rest of the driver code a unified view
13ad49f860SLiviu Dudau  */
14ad49f860SLiviu Dudau 
15c2e7f82dSMihail Atanassov #include <linux/clk.h>
16ad49f860SLiviu Dudau #include <linux/types.h>
17ad49f860SLiviu Dudau #include <linux/io.h>
18ad49f860SLiviu Dudau #include <drm/drmP.h>
19ad49f860SLiviu Dudau #include <video/videomode.h>
20ad49f860SLiviu Dudau #include <video/display_timing.h>
21ad49f860SLiviu Dudau 
22ad49f860SLiviu Dudau #include "malidp_drv.h"
23ad49f860SLiviu Dudau #include "malidp_hw.h"
24ad49f860SLiviu Dudau 
256211b486SBrian Starkey static const struct malidp_format_id malidp500_de_formats[] = {
26ad49f860SLiviu Dudau 	/*    fourcc,   layers supporting the format,     internal id  */
27ad49f860SLiviu Dudau 	{ DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  0 },
28ad49f860SLiviu Dudau 	{ DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  1 },
29ad49f860SLiviu Dudau 	{ DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  2 },
30ad49f860SLiviu Dudau 	{ DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  3 },
31ad49f860SLiviu Dudau 	{ DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  4 },
32ad49f860SLiviu Dudau 	{ DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  5 },
33ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  6 },
34ad49f860SLiviu Dudau 	{ DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  7 },
35ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  8 },
36ad49f860SLiviu Dudau 	{ DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  9 },
37ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 },
38ad49f860SLiviu Dudau 	{ DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 },
39ad49f860SLiviu Dudau 	{ DRM_FORMAT_UYVY, DE_VIDEO1, 12 },
40ad49f860SLiviu Dudau 	{ DRM_FORMAT_YUYV, DE_VIDEO1, 13 },
41ad49f860SLiviu Dudau 	{ DRM_FORMAT_NV12, DE_VIDEO1, 14 },
42ad49f860SLiviu Dudau 	{ DRM_FORMAT_YUV420, DE_VIDEO1, 15 },
43ad49f860SLiviu Dudau };
44ad49f860SLiviu Dudau 
45ad49f860SLiviu Dudau #define MALIDP_ID(__group, __format) \
46ad49f860SLiviu Dudau 	((((__group) & 0x7) << 3) | ((__format) & 0x7))
47ad49f860SLiviu Dudau 
48ad49f860SLiviu Dudau #define MALIDP_COMMON_FORMATS \
49ad49f860SLiviu Dudau 	/*    fourcc,   layers supporting the format,      internal id   */ \
50ad49f860SLiviu Dudau 	{ DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 0) }, \
51ad49f860SLiviu Dudau 	{ DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 1) }, \
52ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 2) }, \
53ad49f860SLiviu Dudau 	{ DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 3) }, \
54ad49f860SLiviu Dudau 	{ DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \
55ad49f860SLiviu Dudau 	{ DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \
56ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \
57ad49f860SLiviu Dudau 	{ DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \
58ad49f860SLiviu Dudau 	{ DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 0) }, \
59ad49f860SLiviu Dudau 	{ DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 1) }, \
60ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 2) }, \
61ad49f860SLiviu Dudau 	{ DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 3) }, \
62ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 0) }, \
63ad49f860SLiviu Dudau 	{ DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 1) }, \
64ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \
65ad49f860SLiviu Dudau 	{ DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \
66ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \
67ad49f860SLiviu Dudau 	{ DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \
68ad49f860SLiviu Dudau 	{ DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) },	\
69ad49f860SLiviu Dudau 	{ DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) },	\
70ad49f860SLiviu Dudau 	{ DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) },	\
71ad49f860SLiviu Dudau 	{ DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }
72ad49f860SLiviu Dudau 
736211b486SBrian Starkey static const struct malidp_format_id malidp550_de_formats[] = {
74ad49f860SLiviu Dudau 	MALIDP_COMMON_FORMATS,
75ad49f860SLiviu Dudau };
76ad49f860SLiviu Dudau 
77ad49f860SLiviu Dudau static const struct malidp_layer malidp500_layers[] = {
786e810eb5SMihail Atanassov 	{ DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB },
796e810eb5SMihail Atanassov 	{ DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 },
806e810eb5SMihail Atanassov 	{ DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 },
81ad49f860SLiviu Dudau };
82ad49f860SLiviu Dudau 
83ad49f860SLiviu Dudau static const struct malidp_layer malidp550_layers[] = {
846e810eb5SMihail Atanassov 	{ DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB },
856e810eb5SMihail Atanassov 	{ DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 },
866e810eb5SMihail Atanassov 	{ DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB },
876e810eb5SMihail Atanassov 	{ DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE, 0 },
88ad49f860SLiviu Dudau };
89ad49f860SLiviu Dudau 
9028ce675bSMihail Atanassov #define SE_N_SCALING_COEFFS	96
9128ce675bSMihail Atanassov static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = {
9228ce675bSMihail Atanassov 	[MALIDP_UPSCALING_COEFFS - 1] = {
9328ce675bSMihail Atanassov 		0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052,
9428ce675bSMihail Atanassov 		0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f,
9528ce675bSMihail Atanassov 		0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a,
9628ce675bSMihail Atanassov 		0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40,
9728ce675bSMihail Atanassov 		0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c,
9828ce675bSMihail Atanassov 		0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5,
9928ce675bSMihail Atanassov 		0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15,
10028ce675bSMihail Atanassov 		0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5,
10128ce675bSMihail Atanassov 		0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0,
10228ce675bSMihail Atanassov 		0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6,
10328ce675bSMihail Atanassov 		0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073,
10428ce675bSMihail Atanassov 		0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001
10528ce675bSMihail Atanassov 	},
10628ce675bSMihail Atanassov 	[MALIDP_DOWNSCALING_1_5_COEFFS - 1] = {
10728ce675bSMihail Atanassov 		0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4,
10828ce675bSMihail Atanassov 		0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c,
10928ce675bSMihail Atanassov 		0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5,
11028ce675bSMihail Atanassov 		0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8,
11128ce675bSMihail Atanassov 		0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba,
11228ce675bSMihail Atanassov 		0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20,
11328ce675bSMihail Atanassov 		0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03,
11428ce675bSMihail Atanassov 		0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d,
11528ce675bSMihail Atanassov 		0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68,
11628ce675bSMihail Atanassov 		0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f,
11728ce675bSMihail Atanassov 		0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62,
11828ce675bSMihail Atanassov 		0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f
11928ce675bSMihail Atanassov 	},
12028ce675bSMihail Atanassov 	[MALIDP_DOWNSCALING_2_COEFFS - 1] = {
12128ce675bSMihail Atanassov 		0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9,
12228ce675bSMihail Atanassov 		0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52,
12328ce675bSMihail Atanassov 		0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158,
12428ce675bSMihail Atanassov 		0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455,
12528ce675bSMihail Atanassov 		0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e,
12628ce675bSMihail Atanassov 		0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887,
12728ce675bSMihail Atanassov 		0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5,
12828ce675bSMihail Atanassov 		0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e,
12928ce675bSMihail Atanassov 		0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d,
13028ce675bSMihail Atanassov 		0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0,
13128ce675bSMihail Atanassov 		0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf,
13228ce675bSMihail Atanassov 		0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03
13328ce675bSMihail Atanassov 	},
13428ce675bSMihail Atanassov 	[MALIDP_DOWNSCALING_2_75_COEFFS - 1] = {
13528ce675bSMihail Atanassov 		0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3,
13628ce675bSMihail Atanassov 		0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106,
13728ce675bSMihail Atanassov 		0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280,
13828ce675bSMihail Atanassov 		0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410,
13928ce675bSMihail Atanassov 		0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533,
14028ce675bSMihail Atanassov 		0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3,
14128ce675bSMihail Atanassov 		0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566,
14228ce675bSMihail Atanassov 		0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468,
14328ce675bSMihail Atanassov 		0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4,
14428ce675bSMihail Atanassov 		0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160,
14528ce675bSMihail Atanassov 		0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f,
14628ce675bSMihail Atanassov 		0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60
14728ce675bSMihail Atanassov 	},
14828ce675bSMihail Atanassov 	[MALIDP_DOWNSCALING_4_COEFFS - 1] = {
14928ce675bSMihail Atanassov 		0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f,
15028ce675bSMihail Atanassov 		0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff,
15128ce675bSMihail Atanassov 		0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd,
15228ce675bSMihail Atanassov 		0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374,
15328ce675bSMihail Atanassov 		0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db,
15428ce675bSMihail Atanassov 		0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a,
15528ce675bSMihail Atanassov 		0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed,
15628ce675bSMihail Atanassov 		0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397,
15728ce675bSMihail Atanassov 		0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb,
15828ce675bSMihail Atanassov 		0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233,
15928ce675bSMihail Atanassov 		0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160,
16028ce675bSMihail Atanassov 		0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9
16128ce675bSMihail Atanassov 	},
16228ce675bSMihail Atanassov };
16328ce675bSMihail Atanassov 
164ad49f860SLiviu Dudau #define MALIDP_DE_DEFAULT_PREFETCH_START	5
165ad49f860SLiviu Dudau 
166ad49f860SLiviu Dudau static int malidp500_query_hw(struct malidp_hw_device *hwdev)
167ad49f860SLiviu Dudau {
168ad49f860SLiviu Dudau 	u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID);
169ad49f860SLiviu Dudau 	/* bit 4 of the CONFIG_ID register holds the line size multiplier */
170ad49f860SLiviu Dudau 	u8 ln_size_mult = conf & 0x10 ? 2 : 1;
171ad49f860SLiviu Dudau 
172ad49f860SLiviu Dudau 	hwdev->min_line_size = 2;
173ad49f860SLiviu Dudau 	hwdev->max_line_size = SZ_2K * ln_size_mult;
174ad49f860SLiviu Dudau 	hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult;
175ad49f860SLiviu Dudau 	hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */
176ad49f860SLiviu Dudau 
177ad49f860SLiviu Dudau 	return 0;
178ad49f860SLiviu Dudau }
179ad49f860SLiviu Dudau 
180ad49f860SLiviu Dudau static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev)
181ad49f860SLiviu Dudau {
182ad49f860SLiviu Dudau 	u32 status, count = 100;
183ad49f860SLiviu Dudau 
184ad49f860SLiviu Dudau 	malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
185ad49f860SLiviu Dudau 	while (count) {
186a6993b21SLiviu Dudau 		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
187ad49f860SLiviu Dudau 		if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
188ad49f860SLiviu Dudau 			break;
189ad49f860SLiviu Dudau 		/*
190ad49f860SLiviu Dudau 		 * entering config mode can take as long as the rendering
191ad49f860SLiviu Dudau 		 * of a full frame, hence the long sleep here
192ad49f860SLiviu Dudau 		 */
193ad49f860SLiviu Dudau 		usleep_range(1000, 10000);
194ad49f860SLiviu Dudau 		count--;
195ad49f860SLiviu Dudau 	}
196ad49f860SLiviu Dudau 	WARN(count == 0, "timeout while entering config mode");
197ad49f860SLiviu Dudau }
198ad49f860SLiviu Dudau 
199ad49f860SLiviu Dudau static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
200ad49f860SLiviu Dudau {
201ad49f860SLiviu Dudau 	u32 status, count = 100;
202ad49f860SLiviu Dudau 
203e64053f0SBrian Starkey 	malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
204ad49f860SLiviu Dudau 	malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
205ad49f860SLiviu Dudau 	while (count) {
206a6993b21SLiviu Dudau 		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
207ad49f860SLiviu Dudau 		if ((status & MALIDP500_DC_CONFIG_REQ) == 0)
208ad49f860SLiviu Dudau 			break;
209ad49f860SLiviu Dudau 		usleep_range(100, 1000);
210ad49f860SLiviu Dudau 		count--;
211ad49f860SLiviu Dudau 	}
212ad49f860SLiviu Dudau 	WARN(count == 0, "timeout while leaving config mode");
213ad49f860SLiviu Dudau }
214ad49f860SLiviu Dudau 
215ad49f860SLiviu Dudau static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
216ad49f860SLiviu Dudau {
217ad49f860SLiviu Dudau 	u32 status;
218ad49f860SLiviu Dudau 
219a6993b21SLiviu Dudau 	status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
220ad49f860SLiviu Dudau 	if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
221ad49f860SLiviu Dudau 		return true;
222ad49f860SLiviu Dudau 
223ad49f860SLiviu Dudau 	return false;
224ad49f860SLiviu Dudau }
225ad49f860SLiviu Dudau 
226ad49f860SLiviu Dudau static void malidp500_set_config_valid(struct malidp_hw_device *hwdev)
227ad49f860SLiviu Dudau {
228ad49f860SLiviu Dudau 	malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
229ad49f860SLiviu Dudau }
230ad49f860SLiviu Dudau 
231ad49f860SLiviu Dudau static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
232ad49f860SLiviu Dudau {
233ad49f860SLiviu Dudau 	u32 val = 0;
234ad49f860SLiviu Dudau 
235ad49f860SLiviu Dudau 	malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL);
236ad49f860SLiviu Dudau 	if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
237ad49f860SLiviu Dudau 		val |= MALIDP500_HSYNCPOL;
238ad49f860SLiviu Dudau 	if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
239ad49f860SLiviu Dudau 		val |= MALIDP500_VSYNCPOL;
240ad49f860SLiviu Dudau 	val |= MALIDP_DE_DEFAULT_PREFETCH_START;
241ad49f860SLiviu Dudau 	malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL);
242ad49f860SLiviu Dudau 
243ad49f860SLiviu Dudau 	/*
244ad49f860SLiviu Dudau 	 * Mali-DP500 encodes the background color like this:
245ad49f860SLiviu Dudau 	 *    - red   @ MALIDP500_BGND_COLOR[12:0]
246ad49f860SLiviu Dudau 	 *    - green @ MALIDP500_BGND_COLOR[27:16]
247ad49f860SLiviu Dudau 	 *    - blue  @ (MALIDP500_BGND_COLOR + 4)[12:0]
248ad49f860SLiviu Dudau 	 */
249ad49f860SLiviu Dudau 	val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) |
250ad49f860SLiviu Dudau 	      (MALIDP_BGND_COLOR_R & 0xfff);
251ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR);
252ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4);
253ad49f860SLiviu Dudau 
254ad49f860SLiviu Dudau 	val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
255ad49f860SLiviu Dudau 		MALIDP_DE_H_BACKPORCH(mode->hback_porch);
256ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
257ad49f860SLiviu Dudau 
258ad49f860SLiviu Dudau 	val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) |
259ad49f860SLiviu Dudau 		MALIDP_DE_V_BACKPORCH(mode->vback_porch);
260ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
261ad49f860SLiviu Dudau 
262ad49f860SLiviu Dudau 	val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
263ad49f860SLiviu Dudau 		MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
264ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
265ad49f860SLiviu Dudau 
266ad49f860SLiviu Dudau 	val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
267ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
268ad49f860SLiviu Dudau 
269ad49f860SLiviu Dudau 	if (mode->flags & DISPLAY_FLAGS_INTERLACED)
270ad49f860SLiviu Dudau 		malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
271ad49f860SLiviu Dudau 	else
272ad49f860SLiviu Dudau 		malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
273ad49f860SLiviu Dudau }
274ad49f860SLiviu Dudau 
275ad49f860SLiviu Dudau static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
276ad49f860SLiviu Dudau {
277ad49f860SLiviu Dudau 	/* RGB888 or BGR888 can't be rotated */
278ad49f860SLiviu Dudau 	if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
279ad49f860SLiviu Dudau 		return -EINVAL;
280ad49f860SLiviu Dudau 
281ad49f860SLiviu Dudau 	/*
282ad49f860SLiviu Dudau 	 * Each layer needs enough rotation memory to fit 8 lines
283ad49f860SLiviu Dudau 	 * worth of pixel data. Required size is then:
284ad49f860SLiviu Dudau 	 *    size = rotated_width * (bpp / 8) * 8;
285ad49f860SLiviu Dudau 	 */
2867ccf281fSLaurent Pinchart 	return w * drm_format_plane_cpp(fmt, 0) * 8;
287ad49f860SLiviu Dudau }
288ad49f860SLiviu Dudau 
28928ce675bSMihail Atanassov static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
29028ce675bSMihail Atanassov 					   u32 direction,
29128ce675bSMihail Atanassov 					   u16 addr,
29228ce675bSMihail Atanassov 					   u8 coeffs_id)
29328ce675bSMihail Atanassov {
29428ce675bSMihail Atanassov 	int i;
29528ce675bSMihail Atanassov 	u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
29628ce675bSMihail Atanassov 
29728ce675bSMihail Atanassov 	malidp_hw_write(hwdev,
29828ce675bSMihail Atanassov 			direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK),
29928ce675bSMihail Atanassov 			scaling_control + MALIDP_SE_COEFFTAB_ADDR);
30028ce675bSMihail Atanassov 	for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i)
30128ce675bSMihail Atanassov 		malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA(
30228ce675bSMihail Atanassov 				dp500_se_scaling_coeffs[coeffs_id][i]),
30328ce675bSMihail Atanassov 				scaling_control + MALIDP_SE_COEFFTAB_DATA);
30428ce675bSMihail Atanassov }
30528ce675bSMihail Atanassov 
30628ce675bSMihail Atanassov static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
30728ce675bSMihail Atanassov 					   struct malidp_se_config *se_config,
30828ce675bSMihail Atanassov 					   struct malidp_se_config *old_config)
30928ce675bSMihail Atanassov {
31028ce675bSMihail Atanassov 	/* Get array indices into dp500_se_scaling_coeffs. */
31128ce675bSMihail Atanassov 	u8 h = (u8)se_config->hcoeff - 1;
31228ce675bSMihail Atanassov 	u8 v = (u8)se_config->vcoeff - 1;
31328ce675bSMihail Atanassov 
31428ce675bSMihail Atanassov 	if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
31528ce675bSMihail Atanassov 		    v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
31628ce675bSMihail Atanassov 		return -EINVAL;
31728ce675bSMihail Atanassov 
31828ce675bSMihail Atanassov 	if ((h == v) && (se_config->hcoeff != old_config->hcoeff ||
31928ce675bSMihail Atanassov 			 se_config->vcoeff != old_config->vcoeff)) {
32028ce675bSMihail Atanassov 		malidp500_se_write_pp_coefftab(hwdev,
32128ce675bSMihail Atanassov 					       (MALIDP_SE_V_COEFFTAB |
32228ce675bSMihail Atanassov 						MALIDP_SE_H_COEFFTAB),
32328ce675bSMihail Atanassov 					       0, v);
32428ce675bSMihail Atanassov 	} else {
32528ce675bSMihail Atanassov 		if (se_config->vcoeff != old_config->vcoeff)
32628ce675bSMihail Atanassov 			malidp500_se_write_pp_coefftab(hwdev,
32728ce675bSMihail Atanassov 						       MALIDP_SE_V_COEFFTAB,
32828ce675bSMihail Atanassov 						       0, v);
32928ce675bSMihail Atanassov 		if (se_config->hcoeff != old_config->hcoeff)
33028ce675bSMihail Atanassov 			malidp500_se_write_pp_coefftab(hwdev,
33128ce675bSMihail Atanassov 						       MALIDP_SE_H_COEFFTAB,
33228ce675bSMihail Atanassov 						       0, h);
33328ce675bSMihail Atanassov 	}
33428ce675bSMihail Atanassov 
33528ce675bSMihail Atanassov 	return 0;
33628ce675bSMihail Atanassov }
33728ce675bSMihail Atanassov 
338c2e7f82dSMihail Atanassov static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
339c2e7f82dSMihail Atanassov 				   struct malidp_se_config *se_config,
340c2e7f82dSMihail Atanassov 				   struct videomode *vm)
341c2e7f82dSMihail Atanassov {
342c2e7f82dSMihail Atanassov 	unsigned long mclk;
343c2e7f82dSMihail Atanassov 	unsigned long pxlclk = vm->pixelclock; /* Hz */
344c2e7f82dSMihail Atanassov 	unsigned long htotal = vm->hactive + vm->hfront_porch +
345c2e7f82dSMihail Atanassov 			       vm->hback_porch + vm->hsync_len;
346c2e7f82dSMihail Atanassov 	unsigned long input_size = se_config->input_w * se_config->input_h;
347c2e7f82dSMihail Atanassov 	unsigned long a = 10;
348c2e7f82dSMihail Atanassov 	long ret;
349c2e7f82dSMihail Atanassov 
350c2e7f82dSMihail Atanassov 	/*
351c2e7f82dSMihail Atanassov 	 * mclk = max(a, 1.5) * pxlclk
352c2e7f82dSMihail Atanassov 	 *
353c2e7f82dSMihail Atanassov 	 * To avoid float calculaiton, using 15 instead of 1.5 and div by
354c2e7f82dSMihail Atanassov 	 * 10 to get mclk.
355c2e7f82dSMihail Atanassov 	 */
356c2e7f82dSMihail Atanassov 	if (se_config->scale_enable) {
357c2e7f82dSMihail Atanassov 		a = 15 * input_size / (htotal * se_config->output_h);
358c2e7f82dSMihail Atanassov 		if (a < 15)
359c2e7f82dSMihail Atanassov 			a = 15;
360c2e7f82dSMihail Atanassov 	}
361c2e7f82dSMihail Atanassov 	mclk = a * pxlclk / 10;
362c2e7f82dSMihail Atanassov 	ret = clk_get_rate(hwdev->mclk);
363c2e7f82dSMihail Atanassov 	if (ret < mclk) {
364c2e7f82dSMihail Atanassov 		DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
365c2e7f82dSMihail Atanassov 				 mclk / 1000);
366c2e7f82dSMihail Atanassov 		return -EINVAL;
367c2e7f82dSMihail Atanassov 	}
368c2e7f82dSMihail Atanassov 	return ret;
369c2e7f82dSMihail Atanassov }
370c2e7f82dSMihail Atanassov 
371ad49f860SLiviu Dudau static int malidp550_query_hw(struct malidp_hw_device *hwdev)
372ad49f860SLiviu Dudau {
373ad49f860SLiviu Dudau 	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
374ad49f860SLiviu Dudau 	u8 ln_size = (conf >> 4) & 0x3, rsize;
375ad49f860SLiviu Dudau 
376ad49f860SLiviu Dudau 	hwdev->min_line_size = 2;
377ad49f860SLiviu Dudau 
378ad49f860SLiviu Dudau 	switch (ln_size) {
379ad49f860SLiviu Dudau 	case 0:
380ad49f860SLiviu Dudau 		hwdev->max_line_size = SZ_2K;
381ad49f860SLiviu Dudau 		/* two banks of 64KB for rotation memory */
382ad49f860SLiviu Dudau 		rsize = 64;
383ad49f860SLiviu Dudau 		break;
384ad49f860SLiviu Dudau 	case 1:
385ad49f860SLiviu Dudau 		hwdev->max_line_size = SZ_4K;
386ad49f860SLiviu Dudau 		/* two banks of 128KB for rotation memory */
387ad49f860SLiviu Dudau 		rsize = 128;
388ad49f860SLiviu Dudau 		break;
389ad49f860SLiviu Dudau 	case 2:
390ad49f860SLiviu Dudau 		hwdev->max_line_size = 1280;
391ad49f860SLiviu Dudau 		/* two banks of 40KB for rotation memory */
392ad49f860SLiviu Dudau 		rsize = 40;
393ad49f860SLiviu Dudau 		break;
394ad49f860SLiviu Dudau 	case 3:
395ad49f860SLiviu Dudau 		/* reserved value */
396ad49f860SLiviu Dudau 		hwdev->max_line_size = 0;
397ad49f860SLiviu Dudau 		return -EINVAL;
398ad49f860SLiviu Dudau 	}
399ad49f860SLiviu Dudau 
400ad49f860SLiviu Dudau 	hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
401ad49f860SLiviu Dudau 	return 0;
402ad49f860SLiviu Dudau }
403ad49f860SLiviu Dudau 
404ad49f860SLiviu Dudau static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
405ad49f860SLiviu Dudau {
406ad49f860SLiviu Dudau 	u32 status, count = 100;
407ad49f860SLiviu Dudau 
408ad49f860SLiviu Dudau 	malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
409ad49f860SLiviu Dudau 	while (count) {
410a6993b21SLiviu Dudau 		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
411ad49f860SLiviu Dudau 		if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
412ad49f860SLiviu Dudau 			break;
413ad49f860SLiviu Dudau 		/*
414ad49f860SLiviu Dudau 		 * entering config mode can take as long as the rendering
415ad49f860SLiviu Dudau 		 * of a full frame, hence the long sleep here
416ad49f860SLiviu Dudau 		 */
417ad49f860SLiviu Dudau 		usleep_range(1000, 10000);
418ad49f860SLiviu Dudau 		count--;
419ad49f860SLiviu Dudau 	}
420ad49f860SLiviu Dudau 	WARN(count == 0, "timeout while entering config mode");
421ad49f860SLiviu Dudau }
422ad49f860SLiviu Dudau 
423ad49f860SLiviu Dudau static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
424ad49f860SLiviu Dudau {
425ad49f860SLiviu Dudau 	u32 status, count = 100;
426ad49f860SLiviu Dudau 
427e64053f0SBrian Starkey 	malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
428ad49f860SLiviu Dudau 	malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
429ad49f860SLiviu Dudau 	while (count) {
430a6993b21SLiviu Dudau 		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
431ad49f860SLiviu Dudau 		if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
432ad49f860SLiviu Dudau 			break;
433ad49f860SLiviu Dudau 		usleep_range(100, 1000);
434ad49f860SLiviu Dudau 		count--;
435ad49f860SLiviu Dudau 	}
436ad49f860SLiviu Dudau 	WARN(count == 0, "timeout while leaving config mode");
437ad49f860SLiviu Dudau }
438ad49f860SLiviu Dudau 
439ad49f860SLiviu Dudau static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
440ad49f860SLiviu Dudau {
441ad49f860SLiviu Dudau 	u32 status;
442ad49f860SLiviu Dudau 
443a6993b21SLiviu Dudau 	status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
444ad49f860SLiviu Dudau 	if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
445ad49f860SLiviu Dudau 		return true;
446ad49f860SLiviu Dudau 
447ad49f860SLiviu Dudau 	return false;
448ad49f860SLiviu Dudau }
449ad49f860SLiviu Dudau 
450ad49f860SLiviu Dudau static void malidp550_set_config_valid(struct malidp_hw_device *hwdev)
451ad49f860SLiviu Dudau {
452ad49f860SLiviu Dudau 	malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
453ad49f860SLiviu Dudau }
454ad49f860SLiviu Dudau 
455ad49f860SLiviu Dudau static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
456ad49f860SLiviu Dudau {
457ad49f860SLiviu Dudau 	u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
458ad49f860SLiviu Dudau 
459ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
460ad49f860SLiviu Dudau 	/*
461ad49f860SLiviu Dudau 	 * Mali-DP550 and Mali-DP650 encode the background color like this:
462ad49f860SLiviu Dudau 	 *   - red   @ MALIDP550_DE_BGND_COLOR[23:16]
463ad49f860SLiviu Dudau 	 *   - green @ MALIDP550_DE_BGND_COLOR[15:8]
464ad49f860SLiviu Dudau 	 *   - blue  @ MALIDP550_DE_BGND_COLOR[7:0]
465ad49f860SLiviu Dudau 	 *
466ad49f860SLiviu Dudau 	 * We need to truncate the least significant 4 bits from the default
467ad49f860SLiviu Dudau 	 * MALIDP_BGND_COLOR_x values
468ad49f860SLiviu Dudau 	 */
469ad49f860SLiviu Dudau 	val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
470ad49f860SLiviu Dudau 	      (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
471ad49f860SLiviu Dudau 	      ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
472ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
473ad49f860SLiviu Dudau 
474ad49f860SLiviu Dudau 	val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
475ad49f860SLiviu Dudau 		MALIDP_DE_H_BACKPORCH(mode->hback_porch);
476ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
477ad49f860SLiviu Dudau 
478ad49f860SLiviu Dudau 	val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
479ad49f860SLiviu Dudau 		MALIDP_DE_V_BACKPORCH(mode->vback_porch);
480ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
481ad49f860SLiviu Dudau 
482ad49f860SLiviu Dudau 	val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
483ad49f860SLiviu Dudau 		MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
484ad49f860SLiviu Dudau 	if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
485ad49f860SLiviu Dudau 		val |= MALIDP550_HSYNCPOL;
486ad49f860SLiviu Dudau 	if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
487ad49f860SLiviu Dudau 		val |= MALIDP550_VSYNCPOL;
488ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
489ad49f860SLiviu Dudau 
490ad49f860SLiviu Dudau 	val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
491ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
492ad49f860SLiviu Dudau 
493ad49f860SLiviu Dudau 	if (mode->flags & DISPLAY_FLAGS_INTERLACED)
494ad49f860SLiviu Dudau 		malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
495ad49f860SLiviu Dudau 	else
496ad49f860SLiviu Dudau 		malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
497ad49f860SLiviu Dudau }
498ad49f860SLiviu Dudau 
499ad49f860SLiviu Dudau static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
500ad49f860SLiviu Dudau {
501ad49f860SLiviu Dudau 	u32 bytes_per_col;
502ad49f860SLiviu Dudau 
503ad49f860SLiviu Dudau 	/* raw RGB888 or BGR888 can't be rotated */
504ad49f860SLiviu Dudau 	if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
505ad49f860SLiviu Dudau 		return -EINVAL;
506ad49f860SLiviu Dudau 
507ad49f860SLiviu Dudau 	switch (fmt) {
508ad49f860SLiviu Dudau 	/* 8 lines at 4 bytes per pixel */
509ad49f860SLiviu Dudau 	case DRM_FORMAT_ARGB2101010:
510ad49f860SLiviu Dudau 	case DRM_FORMAT_ABGR2101010:
511ad49f860SLiviu Dudau 	case DRM_FORMAT_RGBA1010102:
512ad49f860SLiviu Dudau 	case DRM_FORMAT_BGRA1010102:
513ad49f860SLiviu Dudau 	case DRM_FORMAT_ARGB8888:
514ad49f860SLiviu Dudau 	case DRM_FORMAT_ABGR8888:
515ad49f860SLiviu Dudau 	case DRM_FORMAT_RGBA8888:
516ad49f860SLiviu Dudau 	case DRM_FORMAT_BGRA8888:
517ad49f860SLiviu Dudau 	case DRM_FORMAT_XRGB8888:
518ad49f860SLiviu Dudau 	case DRM_FORMAT_XBGR8888:
519ad49f860SLiviu Dudau 	case DRM_FORMAT_RGBX8888:
520ad49f860SLiviu Dudau 	case DRM_FORMAT_BGRX8888:
521ad49f860SLiviu Dudau 	case DRM_FORMAT_RGB888:
522ad49f860SLiviu Dudau 	case DRM_FORMAT_BGR888:
523ad49f860SLiviu Dudau 	/* 16 lines at 2 bytes per pixel */
524ad49f860SLiviu Dudau 	case DRM_FORMAT_RGBA5551:
525ad49f860SLiviu Dudau 	case DRM_FORMAT_ABGR1555:
526ad49f860SLiviu Dudau 	case DRM_FORMAT_RGB565:
527ad49f860SLiviu Dudau 	case DRM_FORMAT_BGR565:
528ad49f860SLiviu Dudau 	case DRM_FORMAT_UYVY:
529ad49f860SLiviu Dudau 	case DRM_FORMAT_YUYV:
530ad49f860SLiviu Dudau 		bytes_per_col = 32;
531ad49f860SLiviu Dudau 		break;
532ad49f860SLiviu Dudau 	/* 16 lines at 1.5 bytes per pixel */
533ad49f860SLiviu Dudau 	case DRM_FORMAT_NV12:
534ad49f860SLiviu Dudau 	case DRM_FORMAT_YUV420:
535ad49f860SLiviu Dudau 		bytes_per_col = 24;
536ad49f860SLiviu Dudau 		break;
537ad49f860SLiviu Dudau 	default:
538ad49f860SLiviu Dudau 		return -EINVAL;
539ad49f860SLiviu Dudau 	}
540ad49f860SLiviu Dudau 
541ad49f860SLiviu Dudau 	return w * bytes_per_col;
542ad49f860SLiviu Dudau }
543ad49f860SLiviu Dudau 
54428ce675bSMihail Atanassov static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
54528ce675bSMihail Atanassov 					   struct malidp_se_config *se_config,
54628ce675bSMihail Atanassov 					   struct malidp_se_config *old_config)
54728ce675bSMihail Atanassov {
54828ce675bSMihail Atanassov 	u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) |
54928ce675bSMihail Atanassov 		   MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK);
55028ce675bSMihail Atanassov 	u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) |
55128ce675bSMihail Atanassov 			MALIDP550_SE_CTL_HCSEL(se_config->hcoeff);
55228ce675bSMihail Atanassov 
55328ce675bSMihail Atanassov 	malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
55428ce675bSMihail Atanassov 	malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
55528ce675bSMihail Atanassov 	return 0;
55628ce675bSMihail Atanassov }
55728ce675bSMihail Atanassov 
558c2e7f82dSMihail Atanassov static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
559c2e7f82dSMihail Atanassov 				   struct malidp_se_config *se_config,
560c2e7f82dSMihail Atanassov 				   struct videomode *vm)
561c2e7f82dSMihail Atanassov {
562c2e7f82dSMihail Atanassov 	unsigned long mclk;
563c2e7f82dSMihail Atanassov 	unsigned long pxlclk = vm->pixelclock;
564c2e7f82dSMihail Atanassov 	unsigned long htotal = vm->hactive + vm->hfront_porch +
565c2e7f82dSMihail Atanassov 			       vm->hback_porch + vm->hsync_len;
566c2e7f82dSMihail Atanassov 	unsigned long numerator = 1, denominator = 1;
567c2e7f82dSMihail Atanassov 	long ret;
568c2e7f82dSMihail Atanassov 
569c2e7f82dSMihail Atanassov 	if (se_config->scale_enable) {
570c2e7f82dSMihail Atanassov 		numerator = max(se_config->input_w, se_config->output_w) *
571c2e7f82dSMihail Atanassov 			    se_config->input_h;
572c2e7f82dSMihail Atanassov 		numerator += se_config->output_w *
573c2e7f82dSMihail Atanassov 			     (se_config->output_h -
574c2e7f82dSMihail Atanassov 			      min(se_config->input_h, se_config->output_h));
575c2e7f82dSMihail Atanassov 		denominator = (htotal - 2) * se_config->output_h;
576c2e7f82dSMihail Atanassov 	}
577c2e7f82dSMihail Atanassov 
578c2e7f82dSMihail Atanassov 	/* mclk can't be slower than pxlclk. */
579c2e7f82dSMihail Atanassov 	if (numerator < denominator)
580c2e7f82dSMihail Atanassov 		numerator = denominator = 1;
581c2e7f82dSMihail Atanassov 	mclk = (pxlclk * numerator) / denominator;
582c2e7f82dSMihail Atanassov 	ret = clk_get_rate(hwdev->mclk);
583c2e7f82dSMihail Atanassov 	if (ret < mclk) {
584c2e7f82dSMihail Atanassov 		DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
585c2e7f82dSMihail Atanassov 				 mclk / 1000);
586c2e7f82dSMihail Atanassov 		return -EINVAL;
587c2e7f82dSMihail Atanassov 	}
588c2e7f82dSMihail Atanassov 	return ret;
589c2e7f82dSMihail Atanassov }
590c2e7f82dSMihail Atanassov 
591846c87a0SLiviu Dudau static int malidp550_enable_memwrite(struct malidp_hw_device *hwdev,
592846c87a0SLiviu Dudau 				     dma_addr_t *addrs, s32 *pitches,
593846c87a0SLiviu Dudau 				     int num_planes, u16 w, u16 h, u32 fmt_id)
594846c87a0SLiviu Dudau {
595846c87a0SLiviu Dudau 	u32 base = MALIDP550_SE_MEMWRITE_BASE;
596846c87a0SLiviu Dudau 	u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
597846c87a0SLiviu Dudau 
598846c87a0SLiviu Dudau 	/* enable the scaling engine block */
599846c87a0SLiviu Dudau 	malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
600846c87a0SLiviu Dudau 
601846c87a0SLiviu Dudau 	malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
602846c87a0SLiviu Dudau 	switch (num_planes) {
603846c87a0SLiviu Dudau 	case 2:
604846c87a0SLiviu Dudau 		malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
605846c87a0SLiviu Dudau 		malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
606846c87a0SLiviu Dudau 		malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
607846c87a0SLiviu Dudau 		/* fall through */
608846c87a0SLiviu Dudau 	case 1:
609846c87a0SLiviu Dudau 		malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
610846c87a0SLiviu Dudau 		malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
611846c87a0SLiviu Dudau 		malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
612846c87a0SLiviu Dudau 		break;
613846c87a0SLiviu Dudau 	default:
614846c87a0SLiviu Dudau 		WARN(1, "Invalid number of planes");
615846c87a0SLiviu Dudau 	}
616846c87a0SLiviu Dudau 
617846c87a0SLiviu Dudau 	malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
618846c87a0SLiviu Dudau 			MALIDP550_SE_MEMWRITE_OUT_SIZE);
619846c87a0SLiviu Dudau 	malidp_hw_setbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
620846c87a0SLiviu Dudau 			  MALIDP550_SE_CONTROL);
621846c87a0SLiviu Dudau 
622846c87a0SLiviu Dudau 	return 0;
623846c87a0SLiviu Dudau }
624846c87a0SLiviu Dudau 
625846c87a0SLiviu Dudau static void malidp550_disable_memwrite(struct malidp_hw_device *hwdev)
626846c87a0SLiviu Dudau {
627846c87a0SLiviu Dudau 	u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
628846c87a0SLiviu Dudau 
629846c87a0SLiviu Dudau 	malidp_hw_clearbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
630846c87a0SLiviu Dudau 			    MALIDP550_SE_CONTROL);
631846c87a0SLiviu Dudau 	malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
632846c87a0SLiviu Dudau }
633846c87a0SLiviu Dudau 
634ad49f860SLiviu Dudau static int malidp650_query_hw(struct malidp_hw_device *hwdev)
635ad49f860SLiviu Dudau {
636ad49f860SLiviu Dudau 	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
637ad49f860SLiviu Dudau 	u8 ln_size = (conf >> 4) & 0x3, rsize;
638ad49f860SLiviu Dudau 
639ad49f860SLiviu Dudau 	hwdev->min_line_size = 4;
640ad49f860SLiviu Dudau 
641ad49f860SLiviu Dudau 	switch (ln_size) {
642ad49f860SLiviu Dudau 	case 0:
643ad49f860SLiviu Dudau 	case 2:
644ad49f860SLiviu Dudau 		/* reserved values */
645ad49f860SLiviu Dudau 		hwdev->max_line_size = 0;
646ad49f860SLiviu Dudau 		return -EINVAL;
647ad49f860SLiviu Dudau 	case 1:
648ad49f860SLiviu Dudau 		hwdev->max_line_size = SZ_4K;
649ad49f860SLiviu Dudau 		/* two banks of 128KB for rotation memory */
650ad49f860SLiviu Dudau 		rsize = 128;
651ad49f860SLiviu Dudau 		break;
652ad49f860SLiviu Dudau 	case 3:
653ad49f860SLiviu Dudau 		hwdev->max_line_size = 2560;
654ad49f860SLiviu Dudau 		/* two banks of 80KB for rotation memory */
655ad49f860SLiviu Dudau 		rsize = 80;
656ad49f860SLiviu Dudau 	}
657ad49f860SLiviu Dudau 
658ad49f860SLiviu Dudau 	hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
659ad49f860SLiviu Dudau 	return 0;
660ad49f860SLiviu Dudau }
661ad49f860SLiviu Dudau 
662a6993b21SLiviu Dudau const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
663ad49f860SLiviu Dudau 	[MALIDP_500] = {
664ad49f860SLiviu Dudau 		.map = {
66502725d31SMihail Atanassov 			.coeffs_base = MALIDP500_COEFFS_BASE,
666ad49f860SLiviu Dudau 			.se_base = MALIDP500_SE_BASE,
667ad49f860SLiviu Dudau 			.dc_base = MALIDP500_DC_BASE,
668ad49f860SLiviu Dudau 			.out_depth_base = MALIDP500_OUTPUT_DEPTH,
669ad49f860SLiviu Dudau 			.features = 0,	/* no CLEARIRQ register */
670ad49f860SLiviu Dudau 			.n_layers = ARRAY_SIZE(malidp500_layers),
671ad49f860SLiviu Dudau 			.layers = malidp500_layers,
672ad49f860SLiviu Dudau 			.de_irq_map = {
673ad49f860SLiviu Dudau 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
674ad49f860SLiviu Dudau 					    MALIDP500_DE_IRQ_AXI_ERR |
675ad49f860SLiviu Dudau 					    MALIDP500_DE_IRQ_VSYNC |
676ad49f860SLiviu Dudau 					    MALIDP500_DE_IRQ_GLOBAL,
677ad49f860SLiviu Dudau 				.vsync_irq = MALIDP500_DE_IRQ_VSYNC,
678ad49f860SLiviu Dudau 			},
679ad49f860SLiviu Dudau 			.se_irq_map = {
68089610dc2SAlison Wang 				.irq_mask = MALIDP500_SE_IRQ_CONF_MODE |
68189610dc2SAlison Wang 					    MALIDP500_SE_IRQ_GLOBAL,
682ad49f860SLiviu Dudau 				.vsync_irq = 0,
683ad49f860SLiviu Dudau 			},
684ad49f860SLiviu Dudau 			.dc_irq_map = {
685ad49f860SLiviu Dudau 				.irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
686ad49f860SLiviu Dudau 				.vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
687ad49f860SLiviu Dudau 			},
6886211b486SBrian Starkey 			.pixel_formats = malidp500_de_formats,
6896211b486SBrian Starkey 			.n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
690a228062cSBrian Starkey 			.bus_align_bytes = 8,
691ad49f860SLiviu Dudau 		},
692ad49f860SLiviu Dudau 		.query_hw = malidp500_query_hw,
693ad49f860SLiviu Dudau 		.enter_config_mode = malidp500_enter_config_mode,
694ad49f860SLiviu Dudau 		.leave_config_mode = malidp500_leave_config_mode,
695ad49f860SLiviu Dudau 		.in_config_mode = malidp500_in_config_mode,
696ad49f860SLiviu Dudau 		.set_config_valid = malidp500_set_config_valid,
697ad49f860SLiviu Dudau 		.modeset = malidp500_modeset,
698ad49f860SLiviu Dudau 		.rotmem_required = malidp500_rotmem_required,
69928ce675bSMihail Atanassov 		.se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
700c2e7f82dSMihail Atanassov 		.se_calc_mclk = malidp500_se_calc_mclk,
70183d642eeSMihail Atanassov 		.features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
702ad49f860SLiviu Dudau 	},
703ad49f860SLiviu Dudau 	[MALIDP_550] = {
704ad49f860SLiviu Dudau 		.map = {
70502725d31SMihail Atanassov 			.coeffs_base = MALIDP550_COEFFS_BASE,
706ad49f860SLiviu Dudau 			.se_base = MALIDP550_SE_BASE,
707ad49f860SLiviu Dudau 			.dc_base = MALIDP550_DC_BASE,
708ad49f860SLiviu Dudau 			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
709ad49f860SLiviu Dudau 			.features = MALIDP_REGMAP_HAS_CLEARIRQ,
710ad49f860SLiviu Dudau 			.n_layers = ARRAY_SIZE(malidp550_layers),
711ad49f860SLiviu Dudau 			.layers = malidp550_layers,
712ad49f860SLiviu Dudau 			.de_irq_map = {
713ad49f860SLiviu Dudau 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
714ad49f860SLiviu Dudau 					    MALIDP550_DE_IRQ_VSYNC,
715ad49f860SLiviu Dudau 				.vsync_irq = MALIDP550_DE_IRQ_VSYNC,
716ad49f860SLiviu Dudau 			},
717ad49f860SLiviu Dudau 			.se_irq_map = {
718ad49f860SLiviu Dudau 				.irq_mask = MALIDP550_SE_IRQ_EOW |
719ad49f860SLiviu Dudau 					    MALIDP550_SE_IRQ_AXI_ERR,
720846c87a0SLiviu Dudau 				.vsync_irq = MALIDP550_SE_IRQ_EOW,
721ad49f860SLiviu Dudau 			},
722ad49f860SLiviu Dudau 			.dc_irq_map = {
723846c87a0SLiviu Dudau 				.irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
724846c87a0SLiviu Dudau 					    MALIDP550_DC_IRQ_SE,
725ad49f860SLiviu Dudau 				.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
726ad49f860SLiviu Dudau 			},
7276211b486SBrian Starkey 			.pixel_formats = malidp550_de_formats,
7286211b486SBrian Starkey 			.n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
729a228062cSBrian Starkey 			.bus_align_bytes = 8,
730ad49f860SLiviu Dudau 		},
731ad49f860SLiviu Dudau 		.query_hw = malidp550_query_hw,
732ad49f860SLiviu Dudau 		.enter_config_mode = malidp550_enter_config_mode,
733ad49f860SLiviu Dudau 		.leave_config_mode = malidp550_leave_config_mode,
734ad49f860SLiviu Dudau 		.in_config_mode = malidp550_in_config_mode,
735ad49f860SLiviu Dudau 		.set_config_valid = malidp550_set_config_valid,
736ad49f860SLiviu Dudau 		.modeset = malidp550_modeset,
737ad49f860SLiviu Dudau 		.rotmem_required = malidp550_rotmem_required,
73828ce675bSMihail Atanassov 		.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
739c2e7f82dSMihail Atanassov 		.se_calc_mclk = malidp550_se_calc_mclk,
740846c87a0SLiviu Dudau 		.enable_memwrite = malidp550_enable_memwrite,
741846c87a0SLiviu Dudau 		.disable_memwrite = malidp550_disable_memwrite,
74283d642eeSMihail Atanassov 		.features = 0,
743ad49f860SLiviu Dudau 	},
744ad49f860SLiviu Dudau 	[MALIDP_650] = {
745ad49f860SLiviu Dudau 		.map = {
74602725d31SMihail Atanassov 			.coeffs_base = MALIDP550_COEFFS_BASE,
747ad49f860SLiviu Dudau 			.se_base = MALIDP550_SE_BASE,
748ad49f860SLiviu Dudau 			.dc_base = MALIDP550_DC_BASE,
749ad49f860SLiviu Dudau 			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
750ad49f860SLiviu Dudau 			.features = MALIDP_REGMAP_HAS_CLEARIRQ,
751ad49f860SLiviu Dudau 			.n_layers = ARRAY_SIZE(malidp550_layers),
752ad49f860SLiviu Dudau 			.layers = malidp550_layers,
753ad49f860SLiviu Dudau 			.de_irq_map = {
754ad49f860SLiviu Dudau 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
755ad49f860SLiviu Dudau 					    MALIDP650_DE_IRQ_DRIFT |
756ad49f860SLiviu Dudau 					    MALIDP550_DE_IRQ_VSYNC,
757ad49f860SLiviu Dudau 				.vsync_irq = MALIDP550_DE_IRQ_VSYNC,
758ad49f860SLiviu Dudau 			},
759ad49f860SLiviu Dudau 			.se_irq_map = {
760ad49f860SLiviu Dudau 				.irq_mask = MALIDP550_SE_IRQ_EOW |
761ad49f860SLiviu Dudau 					    MALIDP550_SE_IRQ_AXI_ERR,
762846c87a0SLiviu Dudau 				.vsync_irq = MALIDP550_SE_IRQ_EOW,
763ad49f860SLiviu Dudau 			},
764ad49f860SLiviu Dudau 			.dc_irq_map = {
765846c87a0SLiviu Dudau 				.irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
766846c87a0SLiviu Dudau 					    MALIDP550_DC_IRQ_SE,
767ad49f860SLiviu Dudau 				.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
768ad49f860SLiviu Dudau 			},
7696211b486SBrian Starkey 			.pixel_formats = malidp550_de_formats,
7706211b486SBrian Starkey 			.n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
771a228062cSBrian Starkey 			.bus_align_bytes = 16,
772ad49f860SLiviu Dudau 		},
773ad49f860SLiviu Dudau 		.query_hw = malidp650_query_hw,
774ad49f860SLiviu Dudau 		.enter_config_mode = malidp550_enter_config_mode,
775ad49f860SLiviu Dudau 		.leave_config_mode = malidp550_leave_config_mode,
776ad49f860SLiviu Dudau 		.in_config_mode = malidp550_in_config_mode,
777ad49f860SLiviu Dudau 		.set_config_valid = malidp550_set_config_valid,
778ad49f860SLiviu Dudau 		.modeset = malidp550_modeset,
779ad49f860SLiviu Dudau 		.rotmem_required = malidp550_rotmem_required,
78028ce675bSMihail Atanassov 		.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
781c2e7f82dSMihail Atanassov 		.se_calc_mclk = malidp550_se_calc_mclk,
782846c87a0SLiviu Dudau 		.enable_memwrite = malidp550_enable_memwrite,
783846c87a0SLiviu Dudau 		.disable_memwrite = malidp550_disable_memwrite,
78483d642eeSMihail Atanassov 		.features = 0,
785ad49f860SLiviu Dudau 	},
786ad49f860SLiviu Dudau };
787ad49f860SLiviu Dudau 
788ad49f860SLiviu Dudau u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
789ad49f860SLiviu Dudau 			   u8 layer_id, u32 format)
790ad49f860SLiviu Dudau {
791ad49f860SLiviu Dudau 	unsigned int i;
792ad49f860SLiviu Dudau 
7936211b486SBrian Starkey 	for (i = 0; i < map->n_pixel_formats; i++) {
7946211b486SBrian Starkey 		if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
7956211b486SBrian Starkey 		    (map->pixel_formats[i].format == format))
7966211b486SBrian Starkey 			return map->pixel_formats[i].id;
797ad49f860SLiviu Dudau 	}
798ad49f860SLiviu Dudau 
799ad49f860SLiviu Dudau 	return MALIDP_INVALID_FORMAT_ID;
800ad49f860SLiviu Dudau }
801ad49f860SLiviu Dudau 
802ad49f860SLiviu Dudau static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
803ad49f860SLiviu Dudau {
804ad49f860SLiviu Dudau 	u32 base = malidp_get_block_base(hwdev, block);
805ad49f860SLiviu Dudau 
806a6993b21SLiviu Dudau 	if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
807ad49f860SLiviu Dudau 		malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
808ad49f860SLiviu Dudau 	else
809ad49f860SLiviu Dudau 		malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
810ad49f860SLiviu Dudau }
811ad49f860SLiviu Dudau 
812ad49f860SLiviu Dudau static irqreturn_t malidp_de_irq(int irq, void *arg)
813ad49f860SLiviu Dudau {
814ad49f860SLiviu Dudau 	struct drm_device *drm = arg;
815ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
816ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev;
817a6993b21SLiviu Dudau 	struct malidp_hw *hw;
818ad49f860SLiviu Dudau 	const struct malidp_irq_map *de;
819ad49f860SLiviu Dudau 	u32 status, mask, dc_status;
820ad49f860SLiviu Dudau 	irqreturn_t ret = IRQ_NONE;
821ad49f860SLiviu Dudau 
822ad49f860SLiviu Dudau 	hwdev = malidp->dev;
823a6993b21SLiviu Dudau 	hw = hwdev->hw;
824a6993b21SLiviu Dudau 	de = &hw->map.de_irq_map;
825ad49f860SLiviu Dudau 
8260df34a80SLiviu Dudau 	/*
8270df34a80SLiviu Dudau 	 * if we are suspended it is likely that we were invoked because
8280df34a80SLiviu Dudau 	 * we share an interrupt line with some other driver, don't try
8290df34a80SLiviu Dudau 	 * to read the hardware registers
8300df34a80SLiviu Dudau 	 */
8310df34a80SLiviu Dudau 	if (hwdev->pm_suspended)
8320df34a80SLiviu Dudau 		return IRQ_NONE;
8330df34a80SLiviu Dudau 
834ad49f860SLiviu Dudau 	/* first handle the config valid IRQ */
835a6993b21SLiviu Dudau 	dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
836a6993b21SLiviu Dudau 	if (dc_status & hw->map.dc_irq_map.vsync_irq) {
837ad49f860SLiviu Dudau 		malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
838d862b2d6SLiviu Dudau 		/* do we have a page flip event? */
839d862b2d6SLiviu Dudau 		if (malidp->event != NULL) {
840d862b2d6SLiviu Dudau 			spin_lock(&drm->event_lock);
841d862b2d6SLiviu Dudau 			drm_crtc_send_vblank_event(&malidp->crtc, malidp->event);
842d862b2d6SLiviu Dudau 			malidp->event = NULL;
843d862b2d6SLiviu Dudau 			spin_unlock(&drm->event_lock);
844d862b2d6SLiviu Dudau 		}
845d862b2d6SLiviu Dudau 		atomic_set(&malidp->config_valid, 1);
846ad49f860SLiviu Dudau 		ret = IRQ_WAKE_THREAD;
847ad49f860SLiviu Dudau 	}
848ad49f860SLiviu Dudau 
849ad49f860SLiviu Dudau 	status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
850ad49f860SLiviu Dudau 	if (!(status & de->irq_mask))
851ad49f860SLiviu Dudau 		return ret;
852ad49f860SLiviu Dudau 
853ad49f860SLiviu Dudau 	mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
854ad49f860SLiviu Dudau 	status &= mask;
855d862b2d6SLiviu Dudau 	if ((status & de->vsync_irq) && malidp->crtc.enabled)
856ad49f860SLiviu Dudau 		drm_crtc_handle_vblank(&malidp->crtc);
857ad49f860SLiviu Dudau 
858ad49f860SLiviu Dudau 	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
859ad49f860SLiviu Dudau 
860ad49f860SLiviu Dudau 	return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
861ad49f860SLiviu Dudau }
862ad49f860SLiviu Dudau 
863ad49f860SLiviu Dudau static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
864ad49f860SLiviu Dudau {
865ad49f860SLiviu Dudau 	struct drm_device *drm = arg;
866ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
867ad49f860SLiviu Dudau 
868ad49f860SLiviu Dudau 	wake_up(&malidp->wq);
869ad49f860SLiviu Dudau 
870ad49f860SLiviu Dudau 	return IRQ_HANDLED;
871ad49f860SLiviu Dudau }
872ad49f860SLiviu Dudau 
873ad49f860SLiviu Dudau int malidp_de_irq_init(struct drm_device *drm, int irq)
874ad49f860SLiviu Dudau {
875ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
876ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev = malidp->dev;
877ad49f860SLiviu Dudau 	int ret;
878ad49f860SLiviu Dudau 
879ad49f860SLiviu Dudau 	/* ensure interrupts are disabled */
880ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
881ad49f860SLiviu Dudau 	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
882ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
883ad49f860SLiviu Dudau 	malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
884ad49f860SLiviu Dudau 
885ad49f860SLiviu Dudau 	ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
886ad49f860SLiviu Dudau 					malidp_de_irq_thread_handler,
887ad49f860SLiviu Dudau 					IRQF_SHARED, "malidp-de", drm);
888ad49f860SLiviu Dudau 	if (ret < 0) {
889ad49f860SLiviu Dudau 		DRM_ERROR("failed to install DE IRQ handler\n");
890ad49f860SLiviu Dudau 		return ret;
891ad49f860SLiviu Dudau 	}
892ad49f860SLiviu Dudau 
893ad49f860SLiviu Dudau 	/* first enable the DC block IRQs */
894ad49f860SLiviu Dudau 	malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
895a6993b21SLiviu Dudau 			     hwdev->hw->map.dc_irq_map.irq_mask);
896ad49f860SLiviu Dudau 
897ad49f860SLiviu Dudau 	/* now enable the DE block IRQs */
898ad49f860SLiviu Dudau 	malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
899a6993b21SLiviu Dudau 			     hwdev->hw->map.de_irq_map.irq_mask);
900ad49f860SLiviu Dudau 
901ad49f860SLiviu Dudau 	return 0;
902ad49f860SLiviu Dudau }
903ad49f860SLiviu Dudau 
904ad49f860SLiviu Dudau void malidp_de_irq_fini(struct drm_device *drm)
905ad49f860SLiviu Dudau {
906ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
907ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev = malidp->dev;
908ad49f860SLiviu Dudau 
909ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
910a6993b21SLiviu Dudau 			      hwdev->hw->map.de_irq_map.irq_mask);
911ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
912a6993b21SLiviu Dudau 			      hwdev->hw->map.dc_irq_map.irq_mask);
913ad49f860SLiviu Dudau }
914ad49f860SLiviu Dudau 
915ad49f860SLiviu Dudau static irqreturn_t malidp_se_irq(int irq, void *arg)
916ad49f860SLiviu Dudau {
917ad49f860SLiviu Dudau 	struct drm_device *drm = arg;
918ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
919ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev = malidp->dev;
920a6993b21SLiviu Dudau 	struct malidp_hw *hw = hwdev->hw;
921a6993b21SLiviu Dudau 	const struct malidp_irq_map *se = &hw->map.se_irq_map;
922ad49f860SLiviu Dudau 	u32 status, mask;
923ad49f860SLiviu Dudau 
9240df34a80SLiviu Dudau 	/*
9250df34a80SLiviu Dudau 	 * if we are suspended it is likely that we were invoked because
9260df34a80SLiviu Dudau 	 * we share an interrupt line with some other driver, don't try
9270df34a80SLiviu Dudau 	 * to read the hardware registers
9280df34a80SLiviu Dudau 	 */
9290df34a80SLiviu Dudau 	if (hwdev->pm_suspended)
9300df34a80SLiviu Dudau 		return IRQ_NONE;
9310df34a80SLiviu Dudau 
932a6993b21SLiviu Dudau 	status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
933a6993b21SLiviu Dudau 	if (!(status & se->irq_mask))
934ad49f860SLiviu Dudau 		return IRQ_NONE;
935ad49f860SLiviu Dudau 
936a6993b21SLiviu Dudau 	mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ);
937a6993b21SLiviu Dudau 	status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
938ad49f860SLiviu Dudau 	status &= mask;
939ad49f860SLiviu Dudau 	/* ToDo: status decoding and firing up of VSYNC and page flip events */
940ad49f860SLiviu Dudau 
941ad49f860SLiviu Dudau 	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
942ad49f860SLiviu Dudau 
943ad49f860SLiviu Dudau 	return IRQ_HANDLED;
944ad49f860SLiviu Dudau }
945ad49f860SLiviu Dudau 
946ad49f860SLiviu Dudau static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
947ad49f860SLiviu Dudau {
948ad49f860SLiviu Dudau 	return IRQ_HANDLED;
949ad49f860SLiviu Dudau }
950ad49f860SLiviu Dudau 
951ad49f860SLiviu Dudau int malidp_se_irq_init(struct drm_device *drm, int irq)
952ad49f860SLiviu Dudau {
953ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
954ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev = malidp->dev;
955ad49f860SLiviu Dudau 	int ret;
956ad49f860SLiviu Dudau 
957ad49f860SLiviu Dudau 	/* ensure interrupts are disabled */
958ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
959ad49f860SLiviu Dudau 	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
960ad49f860SLiviu Dudau 
961ad49f860SLiviu Dudau 	ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
962ad49f860SLiviu Dudau 					malidp_se_irq_thread_handler,
963ad49f860SLiviu Dudau 					IRQF_SHARED, "malidp-se", drm);
964ad49f860SLiviu Dudau 	if (ret < 0) {
965ad49f860SLiviu Dudau 		DRM_ERROR("failed to install SE IRQ handler\n");
966ad49f860SLiviu Dudau 		return ret;
967ad49f860SLiviu Dudau 	}
968ad49f860SLiviu Dudau 
969ad49f860SLiviu Dudau 	malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
970a6993b21SLiviu Dudau 			     hwdev->hw->map.se_irq_map.irq_mask);
971ad49f860SLiviu Dudau 
972ad49f860SLiviu Dudau 	return 0;
973ad49f860SLiviu Dudau }
974ad49f860SLiviu Dudau 
975ad49f860SLiviu Dudau void malidp_se_irq_fini(struct drm_device *drm)
976ad49f860SLiviu Dudau {
977ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
978ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev = malidp->dev;
979ad49f860SLiviu Dudau 
980ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
981a6993b21SLiviu Dudau 			      hwdev->hw->map.se_irq_map.irq_mask);
982ad49f860SLiviu Dudau }
983