132a1795fSJyri Sarha // SPDX-License-Identifier: GPL-2.0
232a1795fSJyri Sarha /*
39410113fSAlexander A. Klimov  * Copyright (C) 2016-2018 Texas Instruments Incorporated - https://www.ti.com/
432a1795fSJyri Sarha  * Author: Jyri Sarha <jsarha@ti.com>
532a1795fSJyri Sarha  */
632a1795fSJyri Sarha 
732a1795fSJyri Sarha #include <linux/clk.h>
832a1795fSJyri Sarha #include <linux/delay.h>
932a1795fSJyri Sarha #include <linux/dma-mapping.h>
1032a1795fSJyri Sarha #include <linux/err.h>
1132a1795fSJyri Sarha #include <linux/interrupt.h>
1232a1795fSJyri Sarha #include <linux/io.h>
1332a1795fSJyri Sarha #include <linux/kernel.h>
1472bd9ea3SVille Syrjälä #include <linux/media-bus-format.h>
1532a1795fSJyri Sarha #include <linux/module.h>
1632a1795fSJyri Sarha #include <linux/mfd/syscon.h>
1732a1795fSJyri Sarha #include <linux/of.h>
1832a1795fSJyri Sarha #include <linux/platform_device.h>
1932a1795fSJyri Sarha #include <linux/pm_runtime.h>
2032a1795fSJyri Sarha #include <linux/regmap.h>
218b87014fSTomi Valkeinen #include <linux/sys_soc.h>
2232a1795fSJyri Sarha 
2390bb087fSVille Syrjälä #include <drm/drm_blend.h>
2432a1795fSJyri Sarha #include <drm/drm_fourcc.h>
256bcfe8eaSDanilo Krummrich #include <drm/drm_fb_dma_helper.h>
26720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h>
274a83c26aSDanilo Krummrich #include <drm/drm_gem_dma_helper.h>
2832a1795fSJyri Sarha #include <drm/drm_panel.h>
2932a1795fSJyri Sarha 
3032a1795fSJyri Sarha #include "tidss_crtc.h"
3132a1795fSJyri Sarha #include "tidss_dispc.h"
3232a1795fSJyri Sarha #include "tidss_drv.h"
3332a1795fSJyri Sarha #include "tidss_irq.h"
3432a1795fSJyri Sarha #include "tidss_plane.h"
3532a1795fSJyri Sarha 
3632a1795fSJyri Sarha #include "tidss_dispc_regs.h"
3732a1795fSJyri Sarha #include "tidss_scale_coefs.h"
3832a1795fSJyri Sarha 
3932a1795fSJyri Sarha static const u16 tidss_k2g_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
4032a1795fSJyri Sarha 	[DSS_REVISION_OFF] =                    0x00,
4132a1795fSJyri Sarha 	[DSS_SYSCONFIG_OFF] =                   0x04,
4232a1795fSJyri Sarha 	[DSS_SYSSTATUS_OFF] =                   0x08,
4332a1795fSJyri Sarha 	[DISPC_IRQ_EOI_OFF] =                   0x20,
4432a1795fSJyri Sarha 	[DISPC_IRQSTATUS_RAW_OFF] =             0x24,
4532a1795fSJyri Sarha 	[DISPC_IRQSTATUS_OFF] =                 0x28,
4632a1795fSJyri Sarha 	[DISPC_IRQENABLE_SET_OFF] =             0x2c,
4732a1795fSJyri Sarha 	[DISPC_IRQENABLE_CLR_OFF] =             0x30,
4832a1795fSJyri Sarha 
4932a1795fSJyri Sarha 	[DISPC_GLOBAL_MFLAG_ATTRIBUTE_OFF] =    0x40,
5032a1795fSJyri Sarha 	[DISPC_GLOBAL_BUFFER_OFF] =             0x44,
5132a1795fSJyri Sarha 
5232a1795fSJyri Sarha 	[DISPC_DBG_CONTROL_OFF] =               0x4c,
5332a1795fSJyri Sarha 	[DISPC_DBG_STATUS_OFF] =                0x50,
5432a1795fSJyri Sarha 
5532a1795fSJyri Sarha 	[DISPC_CLKGATING_DISABLE_OFF] =         0x54,
5632a1795fSJyri Sarha };
5732a1795fSJyri Sarha 
5832a1795fSJyri Sarha const struct dispc_features dispc_k2g_feats = {
5932a1795fSJyri Sarha 	.min_pclk_khz = 4375,
6032a1795fSJyri Sarha 
6132a1795fSJyri Sarha 	.max_pclk_khz = {
6232a1795fSJyri Sarha 		[DISPC_VP_DPI] = 150000,
6332a1795fSJyri Sarha 	},
6432a1795fSJyri Sarha 
6532a1795fSJyri Sarha 	/*
6632a1795fSJyri Sarha 	 * XXX According TRM the RGB input buffer width up to 2560 should
6732a1795fSJyri Sarha 	 *     work on 3 taps, but in practice it only works up to 1280.
6832a1795fSJyri Sarha 	 */
6932a1795fSJyri Sarha 	.scaling = {
7032a1795fSJyri Sarha 		.in_width_max_5tap_rgb = 1280,
7132a1795fSJyri Sarha 		.in_width_max_3tap_rgb = 1280,
7232a1795fSJyri Sarha 		.in_width_max_5tap_yuv = 2560,
7332a1795fSJyri Sarha 		.in_width_max_3tap_yuv = 2560,
7432a1795fSJyri Sarha 		.upscale_limit = 16,
7532a1795fSJyri Sarha 		.downscale_limit_5tap = 4,
7632a1795fSJyri Sarha 		.downscale_limit_3tap = 2,
7732a1795fSJyri Sarha 		/*
7832a1795fSJyri Sarha 		 * The max supported pixel inc value is 255. The value
7932a1795fSJyri Sarha 		 * of pixel inc is calculated like this: 1+(xinc-1)*bpp.
8032a1795fSJyri Sarha 		 * The maximum bpp of all formats supported by the HW
8132a1795fSJyri Sarha 		 * is 8. So the maximum supported xinc value is 32,
8232a1795fSJyri Sarha 		 * because 1+(32-1)*8 < 255 < 1+(33-1)*4.
8332a1795fSJyri Sarha 		 */
8432a1795fSJyri Sarha 		.xinc_max = 32,
8532a1795fSJyri Sarha 	},
8632a1795fSJyri Sarha 
8732a1795fSJyri Sarha 	.subrev = DISPC_K2G,
8832a1795fSJyri Sarha 
8932a1795fSJyri Sarha 	.common = "common",
9032a1795fSJyri Sarha 
9132a1795fSJyri Sarha 	.common_regs = tidss_k2g_common_regs,
9232a1795fSJyri Sarha 
9332a1795fSJyri Sarha 	.num_vps = 1,
9432a1795fSJyri Sarha 	.vp_name = { "vp1" },
9532a1795fSJyri Sarha 	.ovr_name = { "ovr1" },
9632a1795fSJyri Sarha 	.vpclk_name =  { "vp1" },
9732a1795fSJyri Sarha 	.vp_bus_type = { DISPC_VP_DPI },
9832a1795fSJyri Sarha 
9932a1795fSJyri Sarha 	.vp_feat = { .color = {
10032a1795fSJyri Sarha 			.has_ctm = true,
10132a1795fSJyri Sarha 			.gamma_size = 256,
10232a1795fSJyri Sarha 			.gamma_type = TIDSS_GAMMA_8BIT,
10332a1795fSJyri Sarha 		},
10432a1795fSJyri Sarha 	},
10532a1795fSJyri Sarha 
10632a1795fSJyri Sarha 	.num_planes = 1,
10732a1795fSJyri Sarha 	.vid_name = { "vid1" },
10832a1795fSJyri Sarha 	.vid_lite = { false },
10932a1795fSJyri Sarha 	.vid_order = { 0 },
11032a1795fSJyri Sarha };
11132a1795fSJyri Sarha 
11232a1795fSJyri Sarha static const u16 tidss_am65x_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
11332a1795fSJyri Sarha 	[DSS_REVISION_OFF] =			0x4,
11432a1795fSJyri Sarha 	[DSS_SYSCONFIG_OFF] =			0x8,
11532a1795fSJyri Sarha 	[DSS_SYSSTATUS_OFF] =			0x20,
11632a1795fSJyri Sarha 	[DISPC_IRQ_EOI_OFF] =			0x24,
11732a1795fSJyri Sarha 	[DISPC_IRQSTATUS_RAW_OFF] =		0x28,
11832a1795fSJyri Sarha 	[DISPC_IRQSTATUS_OFF] =			0x2c,
11932a1795fSJyri Sarha 	[DISPC_IRQENABLE_SET_OFF] =		0x30,
12032a1795fSJyri Sarha 	[DISPC_IRQENABLE_CLR_OFF] =		0x40,
12132a1795fSJyri Sarha 	[DISPC_VID_IRQENABLE_OFF] =		0x44,
12232a1795fSJyri Sarha 	[DISPC_VID_IRQSTATUS_OFF] =		0x58,
12332a1795fSJyri Sarha 	[DISPC_VP_IRQENABLE_OFF] =		0x70,
12432a1795fSJyri Sarha 	[DISPC_VP_IRQSTATUS_OFF] =		0x7c,
12532a1795fSJyri Sarha 
12632a1795fSJyri Sarha 	[WB_IRQENABLE_OFF] =			0x88,
12732a1795fSJyri Sarha 	[WB_IRQSTATUS_OFF] =			0x8c,
12832a1795fSJyri Sarha 
12932a1795fSJyri Sarha 	[DISPC_GLOBAL_MFLAG_ATTRIBUTE_OFF] =	0x90,
13032a1795fSJyri Sarha 	[DISPC_GLOBAL_OUTPUT_ENABLE_OFF] =	0x94,
13132a1795fSJyri Sarha 	[DISPC_GLOBAL_BUFFER_OFF] =		0x98,
13232a1795fSJyri Sarha 	[DSS_CBA_CFG_OFF] =			0x9c,
13332a1795fSJyri Sarha 	[DISPC_DBG_CONTROL_OFF] =		0xa0,
13432a1795fSJyri Sarha 	[DISPC_DBG_STATUS_OFF] =		0xa4,
13532a1795fSJyri Sarha 	[DISPC_CLKGATING_DISABLE_OFF] =		0xa8,
13632a1795fSJyri Sarha 	[DISPC_SECURE_DISABLE_OFF] =		0xac,
13732a1795fSJyri Sarha };
13832a1795fSJyri Sarha 
13932a1795fSJyri Sarha const struct dispc_features dispc_am65x_feats = {
14032a1795fSJyri Sarha 	.max_pclk_khz = {
14132a1795fSJyri Sarha 		[DISPC_VP_DPI] = 165000,
14232a1795fSJyri Sarha 		[DISPC_VP_OLDI] = 165000,
14332a1795fSJyri Sarha 	},
14432a1795fSJyri Sarha 
14532a1795fSJyri Sarha 	.scaling = {
14632a1795fSJyri Sarha 		.in_width_max_5tap_rgb = 1280,
14732a1795fSJyri Sarha 		.in_width_max_3tap_rgb = 2560,
14832a1795fSJyri Sarha 		.in_width_max_5tap_yuv = 2560,
14932a1795fSJyri Sarha 		.in_width_max_3tap_yuv = 4096,
15032a1795fSJyri Sarha 		.upscale_limit = 16,
15132a1795fSJyri Sarha 		.downscale_limit_5tap = 4,
15232a1795fSJyri Sarha 		.downscale_limit_3tap = 2,
15332a1795fSJyri Sarha 		/*
15432a1795fSJyri Sarha 		 * The max supported pixel inc value is 255. The value
15532a1795fSJyri Sarha 		 * of pixel inc is calculated like this: 1+(xinc-1)*bpp.
15632a1795fSJyri Sarha 		 * The maximum bpp of all formats supported by the HW
15732a1795fSJyri Sarha 		 * is 8. So the maximum supported xinc value is 32,
15832a1795fSJyri Sarha 		 * because 1+(32-1)*8 < 255 < 1+(33-1)*4.
15932a1795fSJyri Sarha 		 */
16032a1795fSJyri Sarha 		.xinc_max = 32,
16132a1795fSJyri Sarha 	},
16232a1795fSJyri Sarha 
16332a1795fSJyri Sarha 	.subrev = DISPC_AM65X,
16432a1795fSJyri Sarha 
16532a1795fSJyri Sarha 	.common = "common",
16632a1795fSJyri Sarha 	.common_regs = tidss_am65x_common_regs,
16732a1795fSJyri Sarha 
16832a1795fSJyri Sarha 	.num_vps = 2,
16932a1795fSJyri Sarha 	.vp_name = { "vp1", "vp2" },
17032a1795fSJyri Sarha 	.ovr_name = { "ovr1", "ovr2" },
17132a1795fSJyri Sarha 	.vpclk_name =  { "vp1", "vp2" },
17232a1795fSJyri Sarha 	.vp_bus_type = { DISPC_VP_OLDI, DISPC_VP_DPI },
17332a1795fSJyri Sarha 
17432a1795fSJyri Sarha 	.vp_feat = { .color = {
17532a1795fSJyri Sarha 			.has_ctm = true,
17632a1795fSJyri Sarha 			.gamma_size = 256,
17732a1795fSJyri Sarha 			.gamma_type = TIDSS_GAMMA_8BIT,
17832a1795fSJyri Sarha 		},
17932a1795fSJyri Sarha 	},
18032a1795fSJyri Sarha 
18132a1795fSJyri Sarha 	.num_planes = 2,
18232a1795fSJyri Sarha 	/* note: vid is plane_id 0 and vidl1 is plane_id 1 */
18332a1795fSJyri Sarha 	.vid_name = { "vid", "vidl1" },
18432a1795fSJyri Sarha 	.vid_lite = { false, true, },
18532a1795fSJyri Sarha 	.vid_order = { 1, 0 },
18632a1795fSJyri Sarha };
18732a1795fSJyri Sarha 
18832a1795fSJyri Sarha static const u16 tidss_j721e_common_regs[DISPC_COMMON_REG_TABLE_LEN] = {
18932a1795fSJyri Sarha 	[DSS_REVISION_OFF] =			0x4,
19032a1795fSJyri Sarha 	[DSS_SYSCONFIG_OFF] =			0x8,
19132a1795fSJyri Sarha 	[DSS_SYSSTATUS_OFF] =			0x20,
19232a1795fSJyri Sarha 	[DISPC_IRQ_EOI_OFF] =			0x80,
19332a1795fSJyri Sarha 	[DISPC_IRQSTATUS_RAW_OFF] =		0x28,
19432a1795fSJyri Sarha 	[DISPC_IRQSTATUS_OFF] =			0x2c,
19532a1795fSJyri Sarha 	[DISPC_IRQENABLE_SET_OFF] =		0x30,
19632a1795fSJyri Sarha 	[DISPC_IRQENABLE_CLR_OFF] =		0x34,
19732a1795fSJyri Sarha 	[DISPC_VID_IRQENABLE_OFF] =		0x38,
19832a1795fSJyri Sarha 	[DISPC_VID_IRQSTATUS_OFF] =		0x48,
19932a1795fSJyri Sarha 	[DISPC_VP_IRQENABLE_OFF] =		0x58,
20032a1795fSJyri Sarha 	[DISPC_VP_IRQSTATUS_OFF] =		0x68,
20132a1795fSJyri Sarha 
20232a1795fSJyri Sarha 	[WB_IRQENABLE_OFF] =			0x78,
20332a1795fSJyri Sarha 	[WB_IRQSTATUS_OFF] =			0x7c,
20432a1795fSJyri Sarha 
20532a1795fSJyri Sarha 	[DISPC_GLOBAL_MFLAG_ATTRIBUTE_OFF] =	0x98,
20632a1795fSJyri Sarha 	[DISPC_GLOBAL_OUTPUT_ENABLE_OFF] =	0x9c,
20732a1795fSJyri Sarha 	[DISPC_GLOBAL_BUFFER_OFF] =		0xa0,
20832a1795fSJyri Sarha 	[DSS_CBA_CFG_OFF] =			0xa4,
20932a1795fSJyri Sarha 	[DISPC_DBG_CONTROL_OFF] =		0xa8,
21032a1795fSJyri Sarha 	[DISPC_DBG_STATUS_OFF] =		0xac,
21132a1795fSJyri Sarha 	[DISPC_CLKGATING_DISABLE_OFF] =		0xb0,
21232a1795fSJyri Sarha 	[DISPC_SECURE_DISABLE_OFF] =		0x90,
21332a1795fSJyri Sarha 
21432a1795fSJyri Sarha 	[FBDC_REVISION_1_OFF] =			0xb8,
21532a1795fSJyri Sarha 	[FBDC_REVISION_2_OFF] =			0xbc,
21632a1795fSJyri Sarha 	[FBDC_REVISION_3_OFF] =			0xc0,
21732a1795fSJyri Sarha 	[FBDC_REVISION_4_OFF] =			0xc4,
21832a1795fSJyri Sarha 	[FBDC_REVISION_5_OFF] =			0xc8,
21932a1795fSJyri Sarha 	[FBDC_REVISION_6_OFF] =			0xcc,
22032a1795fSJyri Sarha 	[FBDC_COMMON_CONTROL_OFF] =		0xd0,
22132a1795fSJyri Sarha 	[FBDC_CONSTANT_COLOR_0_OFF] =		0xd4,
22232a1795fSJyri Sarha 	[FBDC_CONSTANT_COLOR_1_OFF] =		0xd8,
22332a1795fSJyri Sarha 	[DISPC_CONNECTIONS_OFF] =		0xe4,
22432a1795fSJyri Sarha 	[DISPC_MSS_VP1_OFF] =			0xe8,
22532a1795fSJyri Sarha 	[DISPC_MSS_VP3_OFF] =			0xec,
22632a1795fSJyri Sarha };
22732a1795fSJyri Sarha 
22832a1795fSJyri Sarha const struct dispc_features dispc_j721e_feats = {
22932a1795fSJyri Sarha 	.max_pclk_khz = {
23032a1795fSJyri Sarha 		[DISPC_VP_DPI] = 170000,
23132a1795fSJyri Sarha 		[DISPC_VP_INTERNAL] = 600000,
23232a1795fSJyri Sarha 	},
23332a1795fSJyri Sarha 
23432a1795fSJyri Sarha 	.scaling = {
23532a1795fSJyri Sarha 		.in_width_max_5tap_rgb = 2048,
23632a1795fSJyri Sarha 		.in_width_max_3tap_rgb = 4096,
23732a1795fSJyri Sarha 		.in_width_max_5tap_yuv = 4096,
23832a1795fSJyri Sarha 		.in_width_max_3tap_yuv = 4096,
23932a1795fSJyri Sarha 		.upscale_limit = 16,
24032a1795fSJyri Sarha 		.downscale_limit_5tap = 4,
24132a1795fSJyri Sarha 		.downscale_limit_3tap = 2,
24232a1795fSJyri Sarha 		/*
24332a1795fSJyri Sarha 		 * The max supported pixel inc value is 255. The value
24432a1795fSJyri Sarha 		 * of pixel inc is calculated like this: 1+(xinc-1)*bpp.
24532a1795fSJyri Sarha 		 * The maximum bpp of all formats supported by the HW
24632a1795fSJyri Sarha 		 * is 8. So the maximum supported xinc value is 32,
24732a1795fSJyri Sarha 		 * because 1+(32-1)*8 < 255 < 1+(33-1)*4.
24832a1795fSJyri Sarha 		 */
24932a1795fSJyri Sarha 		.xinc_max = 32,
25032a1795fSJyri Sarha 	},
25132a1795fSJyri Sarha 
25232a1795fSJyri Sarha 	.subrev = DISPC_J721E,
25332a1795fSJyri Sarha 
25432a1795fSJyri Sarha 	.common = "common_m",
25532a1795fSJyri Sarha 	.common_regs = tidss_j721e_common_regs,
25632a1795fSJyri Sarha 
25732a1795fSJyri Sarha 	.num_vps = 4,
25832a1795fSJyri Sarha 	.vp_name = { "vp1", "vp2", "vp3", "vp4" },
25932a1795fSJyri Sarha 	.ovr_name = { "ovr1", "ovr2", "ovr3", "ovr4" },
26032a1795fSJyri Sarha 	.vpclk_name = { "vp1", "vp2", "vp3", "vp4" },
26132a1795fSJyri Sarha 	/* Currently hard coded VP routing (see dispc_initial_config()) */
26232a1795fSJyri Sarha 	.vp_bus_type =	{ DISPC_VP_INTERNAL, DISPC_VP_DPI,
26332a1795fSJyri Sarha 			  DISPC_VP_INTERNAL, DISPC_VP_DPI, },
26432a1795fSJyri Sarha 	.vp_feat = { .color = {
26532a1795fSJyri Sarha 			.has_ctm = true,
26632a1795fSJyri Sarha 			.gamma_size = 1024,
26732a1795fSJyri Sarha 			.gamma_type = TIDSS_GAMMA_10BIT,
26832a1795fSJyri Sarha 		},
26932a1795fSJyri Sarha 	},
27032a1795fSJyri Sarha 	.num_planes = 4,
27132a1795fSJyri Sarha 	.vid_name = { "vid1", "vidl1", "vid2", "vidl2" },
27232a1795fSJyri Sarha 	.vid_lite = { 0, 1, 0, 1, },
27332a1795fSJyri Sarha 	.vid_order = { 1, 3, 0, 2 },
27432a1795fSJyri Sarha };
27532a1795fSJyri Sarha 
276ad2ac9dcSAradhya Bhatia const struct dispc_features dispc_am625_feats = {
277ad2ac9dcSAradhya Bhatia 	.max_pclk_khz = {
278ad2ac9dcSAradhya Bhatia 		[DISPC_VP_DPI] = 165000,
279ad2ac9dcSAradhya Bhatia 		[DISPC_VP_INTERNAL] = 170000,
280ad2ac9dcSAradhya Bhatia 	},
281ad2ac9dcSAradhya Bhatia 
282ad2ac9dcSAradhya Bhatia 	.scaling = {
283ad2ac9dcSAradhya Bhatia 		.in_width_max_5tap_rgb = 1280,
284ad2ac9dcSAradhya Bhatia 		.in_width_max_3tap_rgb = 2560,
285ad2ac9dcSAradhya Bhatia 		.in_width_max_5tap_yuv = 2560,
286ad2ac9dcSAradhya Bhatia 		.in_width_max_3tap_yuv = 4096,
287ad2ac9dcSAradhya Bhatia 		.upscale_limit = 16,
288ad2ac9dcSAradhya Bhatia 		.downscale_limit_5tap = 4,
289ad2ac9dcSAradhya Bhatia 		.downscale_limit_3tap = 2,
290ad2ac9dcSAradhya Bhatia 		/*
291ad2ac9dcSAradhya Bhatia 		 * The max supported pixel inc value is 255. The value
292ad2ac9dcSAradhya Bhatia 		 * of pixel inc is calculated like this: 1+(xinc-1)*bpp.
293ad2ac9dcSAradhya Bhatia 		 * The maximum bpp of all formats supported by the HW
294ad2ac9dcSAradhya Bhatia 		 * is 8. So the maximum supported xinc value is 32,
295ad2ac9dcSAradhya Bhatia 		 * because 1+(32-1)*8 < 255 < 1+(33-1)*4.
296ad2ac9dcSAradhya Bhatia 		 */
297ad2ac9dcSAradhya Bhatia 		.xinc_max = 32,
298ad2ac9dcSAradhya Bhatia 	},
299ad2ac9dcSAradhya Bhatia 
300ad2ac9dcSAradhya Bhatia 	.subrev = DISPC_AM625,
301ad2ac9dcSAradhya Bhatia 
302ad2ac9dcSAradhya Bhatia 	.common = "common",
303ad2ac9dcSAradhya Bhatia 	.common_regs = tidss_am65x_common_regs,
304ad2ac9dcSAradhya Bhatia 
305ad2ac9dcSAradhya Bhatia 	.num_vps = 2,
306ad2ac9dcSAradhya Bhatia 	.vp_name = { "vp1", "vp2" },
307ad2ac9dcSAradhya Bhatia 	.ovr_name = { "ovr1", "ovr2" },
308ad2ac9dcSAradhya Bhatia 	.vpclk_name =  { "vp1", "vp2" },
309ad2ac9dcSAradhya Bhatia 	.vp_bus_type = { DISPC_VP_INTERNAL, DISPC_VP_DPI },
310ad2ac9dcSAradhya Bhatia 
311ad2ac9dcSAradhya Bhatia 	.vp_feat = { .color = {
312ad2ac9dcSAradhya Bhatia 			.has_ctm = true,
313ad2ac9dcSAradhya Bhatia 			.gamma_size = 256,
314ad2ac9dcSAradhya Bhatia 			.gamma_type = TIDSS_GAMMA_8BIT,
315ad2ac9dcSAradhya Bhatia 		},
316ad2ac9dcSAradhya Bhatia 	},
317ad2ac9dcSAradhya Bhatia 
318ad2ac9dcSAradhya Bhatia 	.num_planes = 2,
319ad2ac9dcSAradhya Bhatia 	/* note: vid is plane_id 0 and vidl1 is plane_id 1 */
320ad2ac9dcSAradhya Bhatia 	.vid_name = { "vid", "vidl1" },
321ad2ac9dcSAradhya Bhatia 	.vid_lite = { false, true, },
322ad2ac9dcSAradhya Bhatia 	.vid_order = { 1, 0 },
323ad2ac9dcSAradhya Bhatia };
324ad2ac9dcSAradhya Bhatia 
32532a1795fSJyri Sarha static const u16 *dispc_common_regmap;
32632a1795fSJyri Sarha 
32732a1795fSJyri Sarha struct dss_vp_data {
32832a1795fSJyri Sarha 	u32 *gamma_table;
32932a1795fSJyri Sarha };
33032a1795fSJyri Sarha 
33132a1795fSJyri Sarha struct dispc_device {
33232a1795fSJyri Sarha 	struct tidss_device *tidss;
33332a1795fSJyri Sarha 	struct device *dev;
33432a1795fSJyri Sarha 
33532a1795fSJyri Sarha 	void __iomem *base_common;
33632a1795fSJyri Sarha 	void __iomem *base_vid[TIDSS_MAX_PLANES];
33732a1795fSJyri Sarha 	void __iomem *base_ovr[TIDSS_MAX_PORTS];
33832a1795fSJyri Sarha 	void __iomem *base_vp[TIDSS_MAX_PORTS];
33932a1795fSJyri Sarha 
34032a1795fSJyri Sarha 	struct regmap *oldi_io_ctrl;
34132a1795fSJyri Sarha 
34232a1795fSJyri Sarha 	struct clk *vp_clk[TIDSS_MAX_PORTS];
34332a1795fSJyri Sarha 
34432a1795fSJyri Sarha 	const struct dispc_features *feat;
34532a1795fSJyri Sarha 
34632a1795fSJyri Sarha 	struct clk *fclk;
34732a1795fSJyri Sarha 
34832a1795fSJyri Sarha 	bool is_enabled;
34932a1795fSJyri Sarha 
35032a1795fSJyri Sarha 	struct dss_vp_data vp_data[TIDSS_MAX_PORTS];
35132a1795fSJyri Sarha 
35232a1795fSJyri Sarha 	u32 *fourccs;
35332a1795fSJyri Sarha 	u32 num_fourccs;
35432a1795fSJyri Sarha 
35532a1795fSJyri Sarha 	u32 memory_bandwidth_limit;
3568b87014fSTomi Valkeinen 
3578b87014fSTomi Valkeinen 	struct dispc_errata errata;
35832a1795fSJyri Sarha };
35932a1795fSJyri Sarha 
dispc_write(struct dispc_device * dispc,u16 reg,u32 val)36032a1795fSJyri Sarha static void dispc_write(struct dispc_device *dispc, u16 reg, u32 val)
36132a1795fSJyri Sarha {
36232a1795fSJyri Sarha 	iowrite32(val, dispc->base_common + reg);
36332a1795fSJyri Sarha }
36432a1795fSJyri Sarha 
dispc_read(struct dispc_device * dispc,u16 reg)36532a1795fSJyri Sarha static u32 dispc_read(struct dispc_device *dispc, u16 reg)
36632a1795fSJyri Sarha {
36732a1795fSJyri Sarha 	return ioread32(dispc->base_common + reg);
36832a1795fSJyri Sarha }
36932a1795fSJyri Sarha 
37032a1795fSJyri Sarha static
dispc_vid_write(struct dispc_device * dispc,u32 hw_plane,u16 reg,u32 val)37132a1795fSJyri Sarha void dispc_vid_write(struct dispc_device *dispc, u32 hw_plane, u16 reg, u32 val)
37232a1795fSJyri Sarha {
37332a1795fSJyri Sarha 	void __iomem *base = dispc->base_vid[hw_plane];
37432a1795fSJyri Sarha 
37532a1795fSJyri Sarha 	iowrite32(val, base + reg);
37632a1795fSJyri Sarha }
37732a1795fSJyri Sarha 
dispc_vid_read(struct dispc_device * dispc,u32 hw_plane,u16 reg)37832a1795fSJyri Sarha static u32 dispc_vid_read(struct dispc_device *dispc, u32 hw_plane, u16 reg)
37932a1795fSJyri Sarha {
38032a1795fSJyri Sarha 	void __iomem *base = dispc->base_vid[hw_plane];
38132a1795fSJyri Sarha 
38232a1795fSJyri Sarha 	return ioread32(base + reg);
38332a1795fSJyri Sarha }
38432a1795fSJyri Sarha 
dispc_ovr_write(struct dispc_device * dispc,u32 hw_videoport,u16 reg,u32 val)38532a1795fSJyri Sarha static void dispc_ovr_write(struct dispc_device *dispc, u32 hw_videoport,
38632a1795fSJyri Sarha 			    u16 reg, u32 val)
38732a1795fSJyri Sarha {
38832a1795fSJyri Sarha 	void __iomem *base = dispc->base_ovr[hw_videoport];
38932a1795fSJyri Sarha 
39032a1795fSJyri Sarha 	iowrite32(val, base + reg);
39132a1795fSJyri Sarha }
39232a1795fSJyri Sarha 
dispc_ovr_read(struct dispc_device * dispc,u32 hw_videoport,u16 reg)39332a1795fSJyri Sarha static u32 dispc_ovr_read(struct dispc_device *dispc, u32 hw_videoport, u16 reg)
39432a1795fSJyri Sarha {
39532a1795fSJyri Sarha 	void __iomem *base = dispc->base_ovr[hw_videoport];
39632a1795fSJyri Sarha 
39732a1795fSJyri Sarha 	return ioread32(base + reg);
39832a1795fSJyri Sarha }
39932a1795fSJyri Sarha 
dispc_vp_write(struct dispc_device * dispc,u32 hw_videoport,u16 reg,u32 val)40032a1795fSJyri Sarha static void dispc_vp_write(struct dispc_device *dispc, u32 hw_videoport,
40132a1795fSJyri Sarha 			   u16 reg, u32 val)
40232a1795fSJyri Sarha {
40332a1795fSJyri Sarha 	void __iomem *base = dispc->base_vp[hw_videoport];
40432a1795fSJyri Sarha 
40532a1795fSJyri Sarha 	iowrite32(val, base + reg);
40632a1795fSJyri Sarha }
40732a1795fSJyri Sarha 
dispc_vp_read(struct dispc_device * dispc,u32 hw_videoport,u16 reg)40832a1795fSJyri Sarha static u32 dispc_vp_read(struct dispc_device *dispc, u32 hw_videoport, u16 reg)
40932a1795fSJyri Sarha {
41032a1795fSJyri Sarha 	void __iomem *base = dispc->base_vp[hw_videoport];
41132a1795fSJyri Sarha 
41232a1795fSJyri Sarha 	return ioread32(base + reg);
41332a1795fSJyri Sarha }
41432a1795fSJyri Sarha 
41532a1795fSJyri Sarha /*
41632a1795fSJyri Sarha  * TRM gives bitfields as start:end, where start is the higher bit
41732a1795fSJyri Sarha  * number. For example 7:0
41832a1795fSJyri Sarha  */
41932a1795fSJyri Sarha 
FLD_MASK(u32 start,u32 end)42032a1795fSJyri Sarha static u32 FLD_MASK(u32 start, u32 end)
42132a1795fSJyri Sarha {
42232a1795fSJyri Sarha 	return ((1 << (start - end + 1)) - 1) << end;
42332a1795fSJyri Sarha }
42432a1795fSJyri Sarha 
FLD_VAL(u32 val,u32 start,u32 end)42532a1795fSJyri Sarha static u32 FLD_VAL(u32 val, u32 start, u32 end)
42632a1795fSJyri Sarha {
42732a1795fSJyri Sarha 	return (val << end) & FLD_MASK(start, end);
42832a1795fSJyri Sarha }
42932a1795fSJyri Sarha 
FLD_GET(u32 val,u32 start,u32 end)43032a1795fSJyri Sarha static u32 FLD_GET(u32 val, u32 start, u32 end)
43132a1795fSJyri Sarha {
43232a1795fSJyri Sarha 	return (val & FLD_MASK(start, end)) >> end;
43332a1795fSJyri Sarha }
43432a1795fSJyri Sarha 
FLD_MOD(u32 orig,u32 val,u32 start,u32 end)43532a1795fSJyri Sarha static u32 FLD_MOD(u32 orig, u32 val, u32 start, u32 end)
43632a1795fSJyri Sarha {
43732a1795fSJyri Sarha 	return (orig & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end);
43832a1795fSJyri Sarha }
43932a1795fSJyri Sarha 
REG_GET(struct dispc_device * dispc,u32 idx,u32 start,u32 end)44032a1795fSJyri Sarha static u32 REG_GET(struct dispc_device *dispc, u32 idx, u32 start, u32 end)
44132a1795fSJyri Sarha {
44232a1795fSJyri Sarha 	return FLD_GET(dispc_read(dispc, idx), start, end);
44332a1795fSJyri Sarha }
44432a1795fSJyri Sarha 
REG_FLD_MOD(struct dispc_device * dispc,u32 idx,u32 val,u32 start,u32 end)44532a1795fSJyri Sarha static void REG_FLD_MOD(struct dispc_device *dispc, u32 idx, u32 val,
44632a1795fSJyri Sarha 			u32 start, u32 end)
44732a1795fSJyri Sarha {
44832a1795fSJyri Sarha 	dispc_write(dispc, idx, FLD_MOD(dispc_read(dispc, idx), val,
44932a1795fSJyri Sarha 					start, end));
45032a1795fSJyri Sarha }
45132a1795fSJyri Sarha 
VID_REG_GET(struct dispc_device * dispc,u32 hw_plane,u32 idx,u32 start,u32 end)45232a1795fSJyri Sarha static u32 VID_REG_GET(struct dispc_device *dispc, u32 hw_plane, u32 idx,
45332a1795fSJyri Sarha 		       u32 start, u32 end)
45432a1795fSJyri Sarha {
45532a1795fSJyri Sarha 	return FLD_GET(dispc_vid_read(dispc, hw_plane, idx), start, end);
45632a1795fSJyri Sarha }
45732a1795fSJyri Sarha 
VID_REG_FLD_MOD(struct dispc_device * dispc,u32 hw_plane,u32 idx,u32 val,u32 start,u32 end)45832a1795fSJyri Sarha static void VID_REG_FLD_MOD(struct dispc_device *dispc, u32 hw_plane, u32 idx,
45932a1795fSJyri Sarha 			    u32 val, u32 start, u32 end)
46032a1795fSJyri Sarha {
46132a1795fSJyri Sarha 	dispc_vid_write(dispc, hw_plane, idx,
46232a1795fSJyri Sarha 			FLD_MOD(dispc_vid_read(dispc, hw_plane, idx),
46332a1795fSJyri Sarha 				val, start, end));
46432a1795fSJyri Sarha }
46532a1795fSJyri Sarha 
VP_REG_GET(struct dispc_device * dispc,u32 vp,u32 idx,u32 start,u32 end)46632a1795fSJyri Sarha static u32 VP_REG_GET(struct dispc_device *dispc, u32 vp, u32 idx,
46732a1795fSJyri Sarha 		      u32 start, u32 end)
46832a1795fSJyri Sarha {
46932a1795fSJyri Sarha 	return FLD_GET(dispc_vp_read(dispc, vp, idx), start, end);
47032a1795fSJyri Sarha }
47132a1795fSJyri Sarha 
VP_REG_FLD_MOD(struct dispc_device * dispc,u32 vp,u32 idx,u32 val,u32 start,u32 end)47232a1795fSJyri Sarha static void VP_REG_FLD_MOD(struct dispc_device *dispc, u32 vp, u32 idx, u32 val,
47332a1795fSJyri Sarha 			   u32 start, u32 end)
47432a1795fSJyri Sarha {
47532a1795fSJyri Sarha 	dispc_vp_write(dispc, vp, idx, FLD_MOD(dispc_vp_read(dispc, vp, idx),
47632a1795fSJyri Sarha 					       val, start, end));
47732a1795fSJyri Sarha }
47832a1795fSJyri Sarha 
47932a1795fSJyri Sarha __maybe_unused
OVR_REG_GET(struct dispc_device * dispc,u32 ovr,u32 idx,u32 start,u32 end)48032a1795fSJyri Sarha static u32 OVR_REG_GET(struct dispc_device *dispc, u32 ovr, u32 idx,
48132a1795fSJyri Sarha 		       u32 start, u32 end)
48232a1795fSJyri Sarha {
48332a1795fSJyri Sarha 	return FLD_GET(dispc_ovr_read(dispc, ovr, idx), start, end);
48432a1795fSJyri Sarha }
48532a1795fSJyri Sarha 
OVR_REG_FLD_MOD(struct dispc_device * dispc,u32 ovr,u32 idx,u32 val,u32 start,u32 end)48632a1795fSJyri Sarha static void OVR_REG_FLD_MOD(struct dispc_device *dispc, u32 ovr, u32 idx,
48732a1795fSJyri Sarha 			    u32 val, u32 start, u32 end)
48832a1795fSJyri Sarha {
48932a1795fSJyri Sarha 	dispc_ovr_write(dispc, ovr, idx,
49032a1795fSJyri Sarha 			FLD_MOD(dispc_ovr_read(dispc, ovr, idx),
49132a1795fSJyri Sarha 				val, start, end));
49232a1795fSJyri Sarha }
49332a1795fSJyri Sarha 
dispc_vp_irq_from_raw(u32 stat,u32 hw_videoport)49432a1795fSJyri Sarha static dispc_irq_t dispc_vp_irq_from_raw(u32 stat, u32 hw_videoport)
49532a1795fSJyri Sarha {
49632a1795fSJyri Sarha 	dispc_irq_t vp_stat = 0;
49732a1795fSJyri Sarha 
49832a1795fSJyri Sarha 	if (stat & BIT(0))
49932a1795fSJyri Sarha 		vp_stat |= DSS_IRQ_VP_FRAME_DONE(hw_videoport);
50032a1795fSJyri Sarha 	if (stat & BIT(1))
50132a1795fSJyri Sarha 		vp_stat |= DSS_IRQ_VP_VSYNC_EVEN(hw_videoport);
50232a1795fSJyri Sarha 	if (stat & BIT(2))
50332a1795fSJyri Sarha 		vp_stat |= DSS_IRQ_VP_VSYNC_ODD(hw_videoport);
50432a1795fSJyri Sarha 	if (stat & BIT(4))
50532a1795fSJyri Sarha 		vp_stat |= DSS_IRQ_VP_SYNC_LOST(hw_videoport);
50632a1795fSJyri Sarha 
50732a1795fSJyri Sarha 	return vp_stat;
50832a1795fSJyri Sarha }
50932a1795fSJyri Sarha 
dispc_vp_irq_to_raw(dispc_irq_t vpstat,u32 hw_videoport)51032a1795fSJyri Sarha static u32 dispc_vp_irq_to_raw(dispc_irq_t vpstat, u32 hw_videoport)
51132a1795fSJyri Sarha {
51232a1795fSJyri Sarha 	u32 stat = 0;
51332a1795fSJyri Sarha 
51432a1795fSJyri Sarha 	if (vpstat & DSS_IRQ_VP_FRAME_DONE(hw_videoport))
51532a1795fSJyri Sarha 		stat |= BIT(0);
51632a1795fSJyri Sarha 	if (vpstat & DSS_IRQ_VP_VSYNC_EVEN(hw_videoport))
51732a1795fSJyri Sarha 		stat |= BIT(1);
51832a1795fSJyri Sarha 	if (vpstat & DSS_IRQ_VP_VSYNC_ODD(hw_videoport))
51932a1795fSJyri Sarha 		stat |= BIT(2);
52032a1795fSJyri Sarha 	if (vpstat & DSS_IRQ_VP_SYNC_LOST(hw_videoport))
52132a1795fSJyri Sarha 		stat |= BIT(4);
52232a1795fSJyri Sarha 
52332a1795fSJyri Sarha 	return stat;
52432a1795fSJyri Sarha }
52532a1795fSJyri Sarha 
dispc_vid_irq_from_raw(u32 stat,u32 hw_plane)52632a1795fSJyri Sarha static dispc_irq_t dispc_vid_irq_from_raw(u32 stat, u32 hw_plane)
52732a1795fSJyri Sarha {
52832a1795fSJyri Sarha 	dispc_irq_t vid_stat = 0;
52932a1795fSJyri Sarha 
53032a1795fSJyri Sarha 	if (stat & BIT(0))
53132a1795fSJyri Sarha 		vid_stat |= DSS_IRQ_PLANE_FIFO_UNDERFLOW(hw_plane);
53232a1795fSJyri Sarha 
53332a1795fSJyri Sarha 	return vid_stat;
53432a1795fSJyri Sarha }
53532a1795fSJyri Sarha 
dispc_vid_irq_to_raw(dispc_irq_t vidstat,u32 hw_plane)53632a1795fSJyri Sarha static u32 dispc_vid_irq_to_raw(dispc_irq_t vidstat, u32 hw_plane)
53732a1795fSJyri Sarha {
53832a1795fSJyri Sarha 	u32 stat = 0;
53932a1795fSJyri Sarha 
54032a1795fSJyri Sarha 	if (vidstat & DSS_IRQ_PLANE_FIFO_UNDERFLOW(hw_plane))
54132a1795fSJyri Sarha 		stat |= BIT(0);
54232a1795fSJyri Sarha 
54332a1795fSJyri Sarha 	return stat;
54432a1795fSJyri Sarha }
54532a1795fSJyri Sarha 
dispc_k2g_vp_read_irqstatus(struct dispc_device * dispc,u32 hw_videoport)54632a1795fSJyri Sarha static dispc_irq_t dispc_k2g_vp_read_irqstatus(struct dispc_device *dispc,
54732a1795fSJyri Sarha 					       u32 hw_videoport)
54832a1795fSJyri Sarha {
54932a1795fSJyri Sarha 	u32 stat = dispc_vp_read(dispc, hw_videoport, DISPC_VP_K2G_IRQSTATUS);
55032a1795fSJyri Sarha 
55132a1795fSJyri Sarha 	return dispc_vp_irq_from_raw(stat, hw_videoport);
55232a1795fSJyri Sarha }
55332a1795fSJyri Sarha 
dispc_k2g_vp_write_irqstatus(struct dispc_device * dispc,u32 hw_videoport,dispc_irq_t vpstat)55432a1795fSJyri Sarha static void dispc_k2g_vp_write_irqstatus(struct dispc_device *dispc,
55532a1795fSJyri Sarha 					 u32 hw_videoport, dispc_irq_t vpstat)
55632a1795fSJyri Sarha {
55732a1795fSJyri Sarha 	u32 stat = dispc_vp_irq_to_raw(vpstat, hw_videoport);
55832a1795fSJyri Sarha 
55932a1795fSJyri Sarha 	dispc_vp_write(dispc, hw_videoport, DISPC_VP_K2G_IRQSTATUS, stat);
56032a1795fSJyri Sarha }
56132a1795fSJyri Sarha 
dispc_k2g_vid_read_irqstatus(struct dispc_device * dispc,u32 hw_plane)56232a1795fSJyri Sarha static dispc_irq_t dispc_k2g_vid_read_irqstatus(struct dispc_device *dispc,
56332a1795fSJyri Sarha 						u32 hw_plane)
56432a1795fSJyri Sarha {
56532a1795fSJyri Sarha 	u32 stat = dispc_vid_read(dispc, hw_plane, DISPC_VID_K2G_IRQSTATUS);
56632a1795fSJyri Sarha 
56732a1795fSJyri Sarha 	return dispc_vid_irq_from_raw(stat, hw_plane);
56832a1795fSJyri Sarha }
56932a1795fSJyri Sarha 
dispc_k2g_vid_write_irqstatus(struct dispc_device * dispc,u32 hw_plane,dispc_irq_t vidstat)57032a1795fSJyri Sarha static void dispc_k2g_vid_write_irqstatus(struct dispc_device *dispc,
57132a1795fSJyri Sarha 					  u32 hw_plane, dispc_irq_t vidstat)
57232a1795fSJyri Sarha {
57332a1795fSJyri Sarha 	u32 stat = dispc_vid_irq_to_raw(vidstat, hw_plane);
57432a1795fSJyri Sarha 
57532a1795fSJyri Sarha 	dispc_vid_write(dispc, hw_plane, DISPC_VID_K2G_IRQSTATUS, stat);
57632a1795fSJyri Sarha }
57732a1795fSJyri Sarha 
dispc_k2g_vp_read_irqenable(struct dispc_device * dispc,u32 hw_videoport)57832a1795fSJyri Sarha static dispc_irq_t dispc_k2g_vp_read_irqenable(struct dispc_device *dispc,
57932a1795fSJyri Sarha 					       u32 hw_videoport)
58032a1795fSJyri Sarha {
58132a1795fSJyri Sarha 	u32 stat = dispc_vp_read(dispc, hw_videoport, DISPC_VP_K2G_IRQENABLE);
58232a1795fSJyri Sarha 
58332a1795fSJyri Sarha 	return dispc_vp_irq_from_raw(stat, hw_videoport);
58432a1795fSJyri Sarha }
58532a1795fSJyri Sarha 
dispc_k2g_vp_set_irqenable(struct dispc_device * dispc,u32 hw_videoport,dispc_irq_t vpstat)58632a1795fSJyri Sarha static void dispc_k2g_vp_set_irqenable(struct dispc_device *dispc,
58732a1795fSJyri Sarha 				       u32 hw_videoport, dispc_irq_t vpstat)
58832a1795fSJyri Sarha {
58932a1795fSJyri Sarha 	u32 stat = dispc_vp_irq_to_raw(vpstat, hw_videoport);
59032a1795fSJyri Sarha 
59132a1795fSJyri Sarha 	dispc_vp_write(dispc, hw_videoport, DISPC_VP_K2G_IRQENABLE, stat);
59232a1795fSJyri Sarha }
59332a1795fSJyri Sarha 
dispc_k2g_vid_read_irqenable(struct dispc_device * dispc,u32 hw_plane)59432a1795fSJyri Sarha static dispc_irq_t dispc_k2g_vid_read_irqenable(struct dispc_device *dispc,
59532a1795fSJyri Sarha 						u32 hw_plane)
59632a1795fSJyri Sarha {
59732a1795fSJyri Sarha 	u32 stat = dispc_vid_read(dispc, hw_plane, DISPC_VID_K2G_IRQENABLE);
59832a1795fSJyri Sarha 
59932a1795fSJyri Sarha 	return dispc_vid_irq_from_raw(stat, hw_plane);
60032a1795fSJyri Sarha }
60132a1795fSJyri Sarha 
dispc_k2g_vid_set_irqenable(struct dispc_device * dispc,u32 hw_plane,dispc_irq_t vidstat)60232a1795fSJyri Sarha static void dispc_k2g_vid_set_irqenable(struct dispc_device *dispc,
60332a1795fSJyri Sarha 					u32 hw_plane, dispc_irq_t vidstat)
60432a1795fSJyri Sarha {
60532a1795fSJyri Sarha 	u32 stat = dispc_vid_irq_to_raw(vidstat, hw_plane);
60632a1795fSJyri Sarha 
60732a1795fSJyri Sarha 	dispc_vid_write(dispc, hw_plane, DISPC_VID_K2G_IRQENABLE, stat);
60832a1795fSJyri Sarha }
60932a1795fSJyri Sarha 
dispc_k2g_clear_irqstatus(struct dispc_device * dispc,dispc_irq_t mask)61032a1795fSJyri Sarha static void dispc_k2g_clear_irqstatus(struct dispc_device *dispc,
61132a1795fSJyri Sarha 				      dispc_irq_t mask)
61232a1795fSJyri Sarha {
61332a1795fSJyri Sarha 	dispc_k2g_vp_write_irqstatus(dispc, 0, mask);
61432a1795fSJyri Sarha 	dispc_k2g_vid_write_irqstatus(dispc, 0, mask);
61532a1795fSJyri Sarha }
61632a1795fSJyri Sarha 
61732a1795fSJyri Sarha static
dispc_k2g_read_and_clear_irqstatus(struct dispc_device * dispc)61832a1795fSJyri Sarha dispc_irq_t dispc_k2g_read_and_clear_irqstatus(struct dispc_device *dispc)
61932a1795fSJyri Sarha {
62032a1795fSJyri Sarha 	dispc_irq_t stat = 0;
62132a1795fSJyri Sarha 
62232a1795fSJyri Sarha 	/* always clear the top level irqstatus */
62332a1795fSJyri Sarha 	dispc_write(dispc, DISPC_IRQSTATUS,
62432a1795fSJyri Sarha 		    dispc_read(dispc, DISPC_IRQSTATUS));
62532a1795fSJyri Sarha 
62632a1795fSJyri Sarha 	stat |= dispc_k2g_vp_read_irqstatus(dispc, 0);
62732a1795fSJyri Sarha 	stat |= dispc_k2g_vid_read_irqstatus(dispc, 0);
62832a1795fSJyri Sarha 
62932a1795fSJyri Sarha 	dispc_k2g_clear_irqstatus(dispc, stat);
63032a1795fSJyri Sarha 
63132a1795fSJyri Sarha 	return stat;
63232a1795fSJyri Sarha }
63332a1795fSJyri Sarha 
dispc_k2g_read_irqenable(struct dispc_device * dispc)63432a1795fSJyri Sarha static dispc_irq_t dispc_k2g_read_irqenable(struct dispc_device *dispc)
63532a1795fSJyri Sarha {
63632a1795fSJyri Sarha 	dispc_irq_t stat = 0;
63732a1795fSJyri Sarha 
63832a1795fSJyri Sarha 	stat |= dispc_k2g_vp_read_irqenable(dispc, 0);
63932a1795fSJyri Sarha 	stat |= dispc_k2g_vid_read_irqenable(dispc, 0);
64032a1795fSJyri Sarha 
64132a1795fSJyri Sarha 	return stat;
64232a1795fSJyri Sarha }
64332a1795fSJyri Sarha 
64432a1795fSJyri Sarha static
dispc_k2g_set_irqenable(struct dispc_device * dispc,dispc_irq_t mask)64532a1795fSJyri Sarha void dispc_k2g_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask)
64632a1795fSJyri Sarha {
64732a1795fSJyri Sarha 	dispc_irq_t old_mask = dispc_k2g_read_irqenable(dispc);
64832a1795fSJyri Sarha 
64932a1795fSJyri Sarha 	/* clear the irqstatus for newly enabled irqs */
65032a1795fSJyri Sarha 	dispc_k2g_clear_irqstatus(dispc, (mask ^ old_mask) & mask);
65132a1795fSJyri Sarha 
65232a1795fSJyri Sarha 	dispc_k2g_vp_set_irqenable(dispc, 0, mask);
65332a1795fSJyri Sarha 	dispc_k2g_vid_set_irqenable(dispc, 0, mask);
65432a1795fSJyri Sarha 
65532a1795fSJyri Sarha 	dispc_write(dispc, DISPC_IRQENABLE_SET, (1 << 0) | (1 << 7));
65632a1795fSJyri Sarha 
65732a1795fSJyri Sarha 	/* flush posted write */
65832a1795fSJyri Sarha 	dispc_k2g_read_irqenable(dispc);
65932a1795fSJyri Sarha }
66032a1795fSJyri Sarha 
dispc_k3_vp_read_irqstatus(struct dispc_device * dispc,u32 hw_videoport)66132a1795fSJyri Sarha static dispc_irq_t dispc_k3_vp_read_irqstatus(struct dispc_device *dispc,
66232a1795fSJyri Sarha 					      u32 hw_videoport)
66332a1795fSJyri Sarha {
66432a1795fSJyri Sarha 	u32 stat = dispc_read(dispc, DISPC_VP_IRQSTATUS(hw_videoport));
66532a1795fSJyri Sarha 
66632a1795fSJyri Sarha 	return dispc_vp_irq_from_raw(stat, hw_videoport);
66732a1795fSJyri Sarha }
66832a1795fSJyri Sarha 
dispc_k3_vp_write_irqstatus(struct dispc_device * dispc,u32 hw_videoport,dispc_irq_t vpstat)66932a1795fSJyri Sarha static void dispc_k3_vp_write_irqstatus(struct dispc_device *dispc,
67032a1795fSJyri Sarha 					u32 hw_videoport, dispc_irq_t vpstat)
67132a1795fSJyri Sarha {
67232a1795fSJyri Sarha 	u32 stat = dispc_vp_irq_to_raw(vpstat, hw_videoport);
67332a1795fSJyri Sarha 
67432a1795fSJyri Sarha 	dispc_write(dispc, DISPC_VP_IRQSTATUS(hw_videoport), stat);
67532a1795fSJyri Sarha }
67632a1795fSJyri Sarha 
dispc_k3_vid_read_irqstatus(struct dispc_device * dispc,u32 hw_plane)67732a1795fSJyri Sarha static dispc_irq_t dispc_k3_vid_read_irqstatus(struct dispc_device *dispc,
67832a1795fSJyri Sarha 					       u32 hw_plane)
67932a1795fSJyri Sarha {
68032a1795fSJyri Sarha 	u32 stat = dispc_read(dispc, DISPC_VID_IRQSTATUS(hw_plane));
68132a1795fSJyri Sarha 
68232a1795fSJyri Sarha 	return dispc_vid_irq_from_raw(stat, hw_plane);
68332a1795fSJyri Sarha }
68432a1795fSJyri Sarha 
dispc_k3_vid_write_irqstatus(struct dispc_device * dispc,u32 hw_plane,dispc_irq_t vidstat)68532a1795fSJyri Sarha static void dispc_k3_vid_write_irqstatus(struct dispc_device *dispc,
68632a1795fSJyri Sarha 					 u32 hw_plane, dispc_irq_t vidstat)
68732a1795fSJyri Sarha {
68832a1795fSJyri Sarha 	u32 stat = dispc_vid_irq_to_raw(vidstat, hw_plane);
68932a1795fSJyri Sarha 
69032a1795fSJyri Sarha 	dispc_write(dispc, DISPC_VID_IRQSTATUS(hw_plane), stat);
69132a1795fSJyri Sarha }
69232a1795fSJyri Sarha 
dispc_k3_vp_read_irqenable(struct dispc_device * dispc,u32 hw_videoport)69332a1795fSJyri Sarha static dispc_irq_t dispc_k3_vp_read_irqenable(struct dispc_device *dispc,
69432a1795fSJyri Sarha 					      u32 hw_videoport)
69532a1795fSJyri Sarha {
69632a1795fSJyri Sarha 	u32 stat = dispc_read(dispc, DISPC_VP_IRQENABLE(hw_videoport));
69732a1795fSJyri Sarha 
69832a1795fSJyri Sarha 	return dispc_vp_irq_from_raw(stat, hw_videoport);
69932a1795fSJyri Sarha }
70032a1795fSJyri Sarha 
dispc_k3_vp_set_irqenable(struct dispc_device * dispc,u32 hw_videoport,dispc_irq_t vpstat)70132a1795fSJyri Sarha static void dispc_k3_vp_set_irqenable(struct dispc_device *dispc,
70232a1795fSJyri Sarha 				      u32 hw_videoport, dispc_irq_t vpstat)
70332a1795fSJyri Sarha {
70432a1795fSJyri Sarha 	u32 stat = dispc_vp_irq_to_raw(vpstat, hw_videoport);
70532a1795fSJyri Sarha 
70632a1795fSJyri Sarha 	dispc_write(dispc, DISPC_VP_IRQENABLE(hw_videoport), stat);
70732a1795fSJyri Sarha }
70832a1795fSJyri Sarha 
dispc_k3_vid_read_irqenable(struct dispc_device * dispc,u32 hw_plane)70932a1795fSJyri Sarha static dispc_irq_t dispc_k3_vid_read_irqenable(struct dispc_device *dispc,
71032a1795fSJyri Sarha 					       u32 hw_plane)
71132a1795fSJyri Sarha {
71232a1795fSJyri Sarha 	u32 stat = dispc_read(dispc, DISPC_VID_IRQENABLE(hw_plane));
71332a1795fSJyri Sarha 
71432a1795fSJyri Sarha 	return dispc_vid_irq_from_raw(stat, hw_plane);
71532a1795fSJyri Sarha }
71632a1795fSJyri Sarha 
dispc_k3_vid_set_irqenable(struct dispc_device * dispc,u32 hw_plane,dispc_irq_t vidstat)71732a1795fSJyri Sarha static void dispc_k3_vid_set_irqenable(struct dispc_device *dispc,
71832a1795fSJyri Sarha 				       u32 hw_plane, dispc_irq_t vidstat)
71932a1795fSJyri Sarha {
72032a1795fSJyri Sarha 	u32 stat = dispc_vid_irq_to_raw(vidstat, hw_plane);
72132a1795fSJyri Sarha 
72232a1795fSJyri Sarha 	dispc_write(dispc, DISPC_VID_IRQENABLE(hw_plane), stat);
72332a1795fSJyri Sarha }
72432a1795fSJyri Sarha 
72532a1795fSJyri Sarha static
dispc_k3_clear_irqstatus(struct dispc_device * dispc,dispc_irq_t clearmask)72632a1795fSJyri Sarha void dispc_k3_clear_irqstatus(struct dispc_device *dispc, dispc_irq_t clearmask)
72732a1795fSJyri Sarha {
72832a1795fSJyri Sarha 	unsigned int i;
72932a1795fSJyri Sarha 	u32 top_clear = 0;
73032a1795fSJyri Sarha 
73132a1795fSJyri Sarha 	for (i = 0; i < dispc->feat->num_vps; ++i) {
73232a1795fSJyri Sarha 		if (clearmask & DSS_IRQ_VP_MASK(i)) {
73332a1795fSJyri Sarha 			dispc_k3_vp_write_irqstatus(dispc, i, clearmask);
73432a1795fSJyri Sarha 			top_clear |= BIT(i);
73532a1795fSJyri Sarha 		}
73632a1795fSJyri Sarha 	}
73732a1795fSJyri Sarha 	for (i = 0; i < dispc->feat->num_planes; ++i) {
73832a1795fSJyri Sarha 		if (clearmask & DSS_IRQ_PLANE_MASK(i)) {
73932a1795fSJyri Sarha 			dispc_k3_vid_write_irqstatus(dispc, i, clearmask);
74032a1795fSJyri Sarha 			top_clear |= BIT(4 + i);
74132a1795fSJyri Sarha 		}
74232a1795fSJyri Sarha 	}
74332a1795fSJyri Sarha 	if (dispc->feat->subrev == DISPC_K2G)
74432a1795fSJyri Sarha 		return;
74532a1795fSJyri Sarha 
74632a1795fSJyri Sarha 	dispc_write(dispc, DISPC_IRQSTATUS, top_clear);
74732a1795fSJyri Sarha 
74832a1795fSJyri Sarha 	/* Flush posted writes */
74932a1795fSJyri Sarha 	dispc_read(dispc, DISPC_IRQSTATUS);
75032a1795fSJyri Sarha }
75132a1795fSJyri Sarha 
75232a1795fSJyri Sarha static
dispc_k3_read_and_clear_irqstatus(struct dispc_device * dispc)75332a1795fSJyri Sarha dispc_irq_t dispc_k3_read_and_clear_irqstatus(struct dispc_device *dispc)
75432a1795fSJyri Sarha {
75532a1795fSJyri Sarha 	dispc_irq_t status = 0;
75632a1795fSJyri Sarha 	unsigned int i;
75732a1795fSJyri Sarha 
75832a1795fSJyri Sarha 	for (i = 0; i < dispc->feat->num_vps; ++i)
75932a1795fSJyri Sarha 		status |= dispc_k3_vp_read_irqstatus(dispc, i);
76032a1795fSJyri Sarha 
76132a1795fSJyri Sarha 	for (i = 0; i < dispc->feat->num_planes; ++i)
76232a1795fSJyri Sarha 		status |= dispc_k3_vid_read_irqstatus(dispc, i);
76332a1795fSJyri Sarha 
76432a1795fSJyri Sarha 	dispc_k3_clear_irqstatus(dispc, status);
76532a1795fSJyri Sarha 
76632a1795fSJyri Sarha 	return status;
76732a1795fSJyri Sarha }
76832a1795fSJyri Sarha 
dispc_k3_read_irqenable(struct dispc_device * dispc)76932a1795fSJyri Sarha static dispc_irq_t dispc_k3_read_irqenable(struct dispc_device *dispc)
77032a1795fSJyri Sarha {
77132a1795fSJyri Sarha 	dispc_irq_t enable = 0;
77232a1795fSJyri Sarha 	unsigned int i;
77332a1795fSJyri Sarha 
77432a1795fSJyri Sarha 	for (i = 0; i < dispc->feat->num_vps; ++i)
77532a1795fSJyri Sarha 		enable |= dispc_k3_vp_read_irqenable(dispc, i);
77632a1795fSJyri Sarha 
77732a1795fSJyri Sarha 	for (i = 0; i < dispc->feat->num_planes; ++i)
77832a1795fSJyri Sarha 		enable |= dispc_k3_vid_read_irqenable(dispc, i);
77932a1795fSJyri Sarha 
78032a1795fSJyri Sarha 	return enable;
78132a1795fSJyri Sarha }
78232a1795fSJyri Sarha 
dispc_k3_set_irqenable(struct dispc_device * dispc,dispc_irq_t mask)78332a1795fSJyri Sarha static void dispc_k3_set_irqenable(struct dispc_device *dispc,
78432a1795fSJyri Sarha 				   dispc_irq_t mask)
78532a1795fSJyri Sarha {
78632a1795fSJyri Sarha 	unsigned int i;
78732a1795fSJyri Sarha 	u32 main_enable = 0, main_disable = 0;
78832a1795fSJyri Sarha 	dispc_irq_t old_mask;
78932a1795fSJyri Sarha 
79032a1795fSJyri Sarha 	old_mask = dispc_k3_read_irqenable(dispc);
79132a1795fSJyri Sarha 
79232a1795fSJyri Sarha 	/* clear the irqstatus for newly enabled irqs */
79332a1795fSJyri Sarha 	dispc_k3_clear_irqstatus(dispc, (old_mask ^ mask) & mask);
79432a1795fSJyri Sarha 
79532a1795fSJyri Sarha 	for (i = 0; i < dispc->feat->num_vps; ++i) {
79632a1795fSJyri Sarha 		dispc_k3_vp_set_irqenable(dispc, i, mask);
79732a1795fSJyri Sarha 		if (mask & DSS_IRQ_VP_MASK(i))
79832a1795fSJyri Sarha 			main_enable |= BIT(i);		/* VP IRQ */
79932a1795fSJyri Sarha 		else
80032a1795fSJyri Sarha 			main_disable |= BIT(i);		/* VP IRQ */
80132a1795fSJyri Sarha 	}
80232a1795fSJyri Sarha 
80332a1795fSJyri Sarha 	for (i = 0; i < dispc->feat->num_planes; ++i) {
80432a1795fSJyri Sarha 		dispc_k3_vid_set_irqenable(dispc, i, mask);
80532a1795fSJyri Sarha 		if (mask & DSS_IRQ_PLANE_MASK(i))
80632a1795fSJyri Sarha 			main_enable |= BIT(i + 4);	/* VID IRQ */
80732a1795fSJyri Sarha 		else
80832a1795fSJyri Sarha 			main_disable |= BIT(i + 4);	/* VID IRQ */
80932a1795fSJyri Sarha 	}
81032a1795fSJyri Sarha 
81132a1795fSJyri Sarha 	if (main_enable)
81232a1795fSJyri Sarha 		dispc_write(dispc, DISPC_IRQENABLE_SET, main_enable);
81332a1795fSJyri Sarha 
81432a1795fSJyri Sarha 	if (main_disable)
81532a1795fSJyri Sarha 		dispc_write(dispc, DISPC_IRQENABLE_CLR, main_disable);
81632a1795fSJyri Sarha 
81732a1795fSJyri Sarha 	/* Flush posted writes */
81832a1795fSJyri Sarha 	dispc_read(dispc, DISPC_IRQENABLE_SET);
81932a1795fSJyri Sarha }
82032a1795fSJyri Sarha 
dispc_read_and_clear_irqstatus(struct dispc_device * dispc)82132a1795fSJyri Sarha dispc_irq_t dispc_read_and_clear_irqstatus(struct dispc_device *dispc)
82232a1795fSJyri Sarha {
82332a1795fSJyri Sarha 	switch (dispc->feat->subrev) {
82432a1795fSJyri Sarha 	case DISPC_K2G:
82532a1795fSJyri Sarha 		return dispc_k2g_read_and_clear_irqstatus(dispc);
826ad2ac9dcSAradhya Bhatia 	case DISPC_AM625:
82732a1795fSJyri Sarha 	case DISPC_AM65X:
82832a1795fSJyri Sarha 	case DISPC_J721E:
82932a1795fSJyri Sarha 		return dispc_k3_read_and_clear_irqstatus(dispc);
83032a1795fSJyri Sarha 	default:
83132a1795fSJyri Sarha 		WARN_ON(1);
83232a1795fSJyri Sarha 		return 0;
83332a1795fSJyri Sarha 	}
83432a1795fSJyri Sarha }
83532a1795fSJyri Sarha 
dispc_set_irqenable(struct dispc_device * dispc,dispc_irq_t mask)83632a1795fSJyri Sarha void dispc_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask)
83732a1795fSJyri Sarha {
83832a1795fSJyri Sarha 	switch (dispc->feat->subrev) {
83932a1795fSJyri Sarha 	case DISPC_K2G:
84032a1795fSJyri Sarha 		dispc_k2g_set_irqenable(dispc, mask);
84132a1795fSJyri Sarha 		break;
842ad2ac9dcSAradhya Bhatia 	case DISPC_AM625:
84332a1795fSJyri Sarha 	case DISPC_AM65X:
84432a1795fSJyri Sarha 	case DISPC_J721E:
84532a1795fSJyri Sarha 		dispc_k3_set_irqenable(dispc, mask);
84632a1795fSJyri Sarha 		break;
84732a1795fSJyri Sarha 	default:
84832a1795fSJyri Sarha 		WARN_ON(1);
84932a1795fSJyri Sarha 		break;
85032a1795fSJyri Sarha 	}
85132a1795fSJyri Sarha }
85232a1795fSJyri Sarha 
85332a1795fSJyri Sarha enum dispc_oldi_mode_reg_val { SPWG_18 = 0, JEIDA_24 = 1, SPWG_24 = 2 };
85432a1795fSJyri Sarha 
85532a1795fSJyri Sarha struct dispc_bus_format {
85632a1795fSJyri Sarha 	u32 bus_fmt;
85732a1795fSJyri Sarha 	u32 data_width;
85832a1795fSJyri Sarha 	bool is_oldi_fmt;
85932a1795fSJyri Sarha 	enum dispc_oldi_mode_reg_val oldi_mode_reg_val;
86032a1795fSJyri Sarha };
86132a1795fSJyri Sarha 
86232a1795fSJyri Sarha static const struct dispc_bus_format dispc_bus_formats[] = {
86332a1795fSJyri Sarha 	{ MEDIA_BUS_FMT_RGB444_1X12,		12, false, 0 },
86432a1795fSJyri Sarha 	{ MEDIA_BUS_FMT_RGB565_1X16,		16, false, 0 },
86532a1795fSJyri Sarha 	{ MEDIA_BUS_FMT_RGB666_1X18,		18, false, 0 },
86632a1795fSJyri Sarha 	{ MEDIA_BUS_FMT_RGB888_1X24,		24, false, 0 },
86732a1795fSJyri Sarha 	{ MEDIA_BUS_FMT_RGB101010_1X30,		30, false, 0 },
86832a1795fSJyri Sarha 	{ MEDIA_BUS_FMT_RGB121212_1X36,		36, false, 0 },
86932a1795fSJyri Sarha 	{ MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,	18, true, SPWG_18 },
87032a1795fSJyri Sarha 	{ MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,	24, true, SPWG_24 },
87132a1795fSJyri Sarha 	{ MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,	24, true, JEIDA_24 },
87232a1795fSJyri Sarha };
87332a1795fSJyri Sarha 
87432a1795fSJyri Sarha static const
dispc_vp_find_bus_fmt(struct dispc_device * dispc,u32 hw_videoport,u32 bus_fmt,u32 bus_flags)87532a1795fSJyri Sarha struct dispc_bus_format *dispc_vp_find_bus_fmt(struct dispc_device *dispc,
87632a1795fSJyri Sarha 					       u32 hw_videoport,
87732a1795fSJyri Sarha 					       u32 bus_fmt, u32 bus_flags)
87832a1795fSJyri Sarha {
87932a1795fSJyri Sarha 	unsigned int i;
88032a1795fSJyri Sarha 
88132a1795fSJyri Sarha 	for (i = 0; i < ARRAY_SIZE(dispc_bus_formats); ++i) {
88232a1795fSJyri Sarha 		if (dispc_bus_formats[i].bus_fmt == bus_fmt)
88332a1795fSJyri Sarha 			return &dispc_bus_formats[i];
88432a1795fSJyri Sarha 	}
88532a1795fSJyri Sarha 
88632a1795fSJyri Sarha 	return NULL;
88732a1795fSJyri Sarha }
88832a1795fSJyri Sarha 
dispc_vp_bus_check(struct dispc_device * dispc,u32 hw_videoport,const struct drm_crtc_state * state)88932a1795fSJyri Sarha int dispc_vp_bus_check(struct dispc_device *dispc, u32 hw_videoport,
89032a1795fSJyri Sarha 		       const struct drm_crtc_state *state)
89132a1795fSJyri Sarha {
89232a1795fSJyri Sarha 	const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state);
89332a1795fSJyri Sarha 	const struct dispc_bus_format *fmt;
89432a1795fSJyri Sarha 
89532a1795fSJyri Sarha 	fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format,
89632a1795fSJyri Sarha 				    tstate->bus_flags);
89732a1795fSJyri Sarha 	if (!fmt) {
89832a1795fSJyri Sarha 		dev_dbg(dispc->dev, "%s: Unsupported bus format: %u\n",
89932a1795fSJyri Sarha 			__func__, tstate->bus_format);
90032a1795fSJyri Sarha 		return -EINVAL;
90132a1795fSJyri Sarha 	}
90232a1795fSJyri Sarha 
90332a1795fSJyri Sarha 	if (dispc->feat->vp_bus_type[hw_videoport] != DISPC_VP_OLDI &&
90432a1795fSJyri Sarha 	    fmt->is_oldi_fmt) {
90532a1795fSJyri Sarha 		dev_dbg(dispc->dev, "%s: %s is not OLDI-port\n",
90632a1795fSJyri Sarha 			__func__, dispc->feat->vp_name[hw_videoport]);
90732a1795fSJyri Sarha 		return -EINVAL;
90832a1795fSJyri Sarha 	}
90932a1795fSJyri Sarha 
91032a1795fSJyri Sarha 	return 0;
91132a1795fSJyri Sarha }
91232a1795fSJyri Sarha 
dispc_oldi_tx_power(struct dispc_device * dispc,bool power)91332a1795fSJyri Sarha static void dispc_oldi_tx_power(struct dispc_device *dispc, bool power)
91432a1795fSJyri Sarha {
91532a1795fSJyri Sarha 	u32 val = power ? 0 : OLDI_PWRDN_TX;
91632a1795fSJyri Sarha 
91732a1795fSJyri Sarha 	if (WARN_ON(!dispc->oldi_io_ctrl))
91832a1795fSJyri Sarha 		return;
91932a1795fSJyri Sarha 
92032a1795fSJyri Sarha 	regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT0_IO_CTRL,
92132a1795fSJyri Sarha 			   OLDI_PWRDN_TX, val);
92232a1795fSJyri Sarha 	regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT1_IO_CTRL,
92332a1795fSJyri Sarha 			   OLDI_PWRDN_TX, val);
92432a1795fSJyri Sarha 	regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT2_IO_CTRL,
92532a1795fSJyri Sarha 			   OLDI_PWRDN_TX, val);
92632a1795fSJyri Sarha 	regmap_update_bits(dispc->oldi_io_ctrl, OLDI_DAT3_IO_CTRL,
92732a1795fSJyri Sarha 			   OLDI_PWRDN_TX, val);
92832a1795fSJyri Sarha 	regmap_update_bits(dispc->oldi_io_ctrl, OLDI_CLK_IO_CTRL,
92932a1795fSJyri Sarha 			   OLDI_PWRDN_TX, val);
93032a1795fSJyri Sarha }
93132a1795fSJyri Sarha 
dispc_set_num_datalines(struct dispc_device * dispc,u32 hw_videoport,int num_lines)93232a1795fSJyri Sarha static void dispc_set_num_datalines(struct dispc_device *dispc,
93332a1795fSJyri Sarha 				    u32 hw_videoport, int num_lines)
93432a1795fSJyri Sarha {
93532a1795fSJyri Sarha 	int v;
93632a1795fSJyri Sarha 
93732a1795fSJyri Sarha 	switch (num_lines) {
93832a1795fSJyri Sarha 	case 12:
93932a1795fSJyri Sarha 		v = 0; break;
94032a1795fSJyri Sarha 	case 16:
94132a1795fSJyri Sarha 		v = 1; break;
94232a1795fSJyri Sarha 	case 18:
94332a1795fSJyri Sarha 		v = 2; break;
94432a1795fSJyri Sarha 	case 24:
94532a1795fSJyri Sarha 		v = 3; break;
94632a1795fSJyri Sarha 	case 30:
94732a1795fSJyri Sarha 		v = 4; break;
94832a1795fSJyri Sarha 	case 36:
94932a1795fSJyri Sarha 		v = 5; break;
95032a1795fSJyri Sarha 	default:
95132a1795fSJyri Sarha 		WARN_ON(1);
95232a1795fSJyri Sarha 		v = 3;
95332a1795fSJyri Sarha 	}
95432a1795fSJyri Sarha 
95532a1795fSJyri Sarha 	VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, v, 10, 8);
95632a1795fSJyri Sarha }
95732a1795fSJyri Sarha 
dispc_enable_oldi(struct dispc_device * dispc,u32 hw_videoport,const struct dispc_bus_format * fmt)95832a1795fSJyri Sarha static void dispc_enable_oldi(struct dispc_device *dispc, u32 hw_videoport,
95932a1795fSJyri Sarha 			      const struct dispc_bus_format *fmt)
96032a1795fSJyri Sarha {
96132a1795fSJyri Sarha 	u32 oldi_cfg = 0;
96232a1795fSJyri Sarha 	u32 oldi_reset_bit = BIT(5 + hw_videoport);
96332a1795fSJyri Sarha 	int count = 0;
96432a1795fSJyri Sarha 
96532a1795fSJyri Sarha 	/*
96632a1795fSJyri Sarha 	 * For the moment DUALMODESYNC, MASTERSLAVE, MODE, and SRC
96732a1795fSJyri Sarha 	 * bits of DISPC_VP_DSS_OLDI_CFG are set statically to 0.
96832a1795fSJyri Sarha 	 */
96932a1795fSJyri Sarha 
97032a1795fSJyri Sarha 	if (fmt->data_width == 24)
97132a1795fSJyri Sarha 		oldi_cfg |= BIT(8); /* MSB */
97232a1795fSJyri Sarha 	else if (fmt->data_width != 18)
97332a1795fSJyri Sarha 		dev_warn(dispc->dev, "%s: %d port width not supported\n",
97432a1795fSJyri Sarha 			 __func__, fmt->data_width);
97532a1795fSJyri Sarha 
97632a1795fSJyri Sarha 	oldi_cfg |= BIT(7); /* DEPOL */
97732a1795fSJyri Sarha 
97832a1795fSJyri Sarha 	oldi_cfg = FLD_MOD(oldi_cfg, fmt->oldi_mode_reg_val, 3, 1);
97932a1795fSJyri Sarha 
98032a1795fSJyri Sarha 	oldi_cfg |= BIT(12); /* SOFTRST */
98132a1795fSJyri Sarha 
98232a1795fSJyri Sarha 	oldi_cfg |= BIT(0); /* ENABLE */
98332a1795fSJyri Sarha 
98432a1795fSJyri Sarha 	dispc_vp_write(dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, oldi_cfg);
98532a1795fSJyri Sarha 
98632a1795fSJyri Sarha 	while (!(oldi_reset_bit & dispc_read(dispc, DSS_SYSSTATUS)) &&
98732a1795fSJyri Sarha 	       count < 10000)
98832a1795fSJyri Sarha 		count++;
98932a1795fSJyri Sarha 
99032a1795fSJyri Sarha 	if (!(oldi_reset_bit & dispc_read(dispc, DSS_SYSSTATUS)))
99132a1795fSJyri Sarha 		dev_warn(dispc->dev, "%s: timeout waiting OLDI reset done\n",
99232a1795fSJyri Sarha 			 __func__);
99332a1795fSJyri Sarha }
99432a1795fSJyri Sarha 
dispc_vp_prepare(struct dispc_device * dispc,u32 hw_videoport,const struct drm_crtc_state * state)99532a1795fSJyri Sarha void dispc_vp_prepare(struct dispc_device *dispc, u32 hw_videoport,
99632a1795fSJyri Sarha 		      const struct drm_crtc_state *state)
99732a1795fSJyri Sarha {
99832a1795fSJyri Sarha 	const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state);
99932a1795fSJyri Sarha 	const struct dispc_bus_format *fmt;
100032a1795fSJyri Sarha 
100132a1795fSJyri Sarha 	fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format,
100232a1795fSJyri Sarha 				    tstate->bus_flags);
100332a1795fSJyri Sarha 
100432a1795fSJyri Sarha 	if (WARN_ON(!fmt))
100532a1795fSJyri Sarha 		return;
100632a1795fSJyri Sarha 
100732a1795fSJyri Sarha 	if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) {
100832a1795fSJyri Sarha 		dispc_oldi_tx_power(dispc, true);
100932a1795fSJyri Sarha 
101032a1795fSJyri Sarha 		dispc_enable_oldi(dispc, hw_videoport, fmt);
101132a1795fSJyri Sarha 	}
101232a1795fSJyri Sarha }
101332a1795fSJyri Sarha 
dispc_vp_enable(struct dispc_device * dispc,u32 hw_videoport,const struct drm_crtc_state * state)101432a1795fSJyri Sarha void dispc_vp_enable(struct dispc_device *dispc, u32 hw_videoport,
101532a1795fSJyri Sarha 		     const struct drm_crtc_state *state)
101632a1795fSJyri Sarha {
101732a1795fSJyri Sarha 	const struct drm_display_mode *mode = &state->adjusted_mode;
101832a1795fSJyri Sarha 	const struct tidss_crtc_state *tstate = to_tidss_crtc_state(state);
101932a1795fSJyri Sarha 	bool align, onoff, rf, ieo, ipc, ihs, ivs;
102032a1795fSJyri Sarha 	const struct dispc_bus_format *fmt;
102132a1795fSJyri Sarha 	u32 hsw, hfp, hbp, vsw, vfp, vbp;
102232a1795fSJyri Sarha 
102332a1795fSJyri Sarha 	fmt = dispc_vp_find_bus_fmt(dispc, hw_videoport, tstate->bus_format,
102432a1795fSJyri Sarha 				    tstate->bus_flags);
102532a1795fSJyri Sarha 
102632a1795fSJyri Sarha 	if (WARN_ON(!fmt))
102732a1795fSJyri Sarha 		return;
102832a1795fSJyri Sarha 
102932a1795fSJyri Sarha 	dispc_set_num_datalines(dispc, hw_videoport, fmt->data_width);
103032a1795fSJyri Sarha 
103132a1795fSJyri Sarha 	hfp = mode->hsync_start - mode->hdisplay;
103232a1795fSJyri Sarha 	hsw = mode->hsync_end - mode->hsync_start;
103332a1795fSJyri Sarha 	hbp = mode->htotal - mode->hsync_end;
103432a1795fSJyri Sarha 
103532a1795fSJyri Sarha 	vfp = mode->vsync_start - mode->vdisplay;
103632a1795fSJyri Sarha 	vsw = mode->vsync_end - mode->vsync_start;
103732a1795fSJyri Sarha 	vbp = mode->vtotal - mode->vsync_end;
103832a1795fSJyri Sarha 
103932a1795fSJyri Sarha 	dispc_vp_write(dispc, hw_videoport, DISPC_VP_TIMING_H,
104032a1795fSJyri Sarha 		       FLD_VAL(hsw - 1, 7, 0) |
104132a1795fSJyri Sarha 		       FLD_VAL(hfp - 1, 19, 8) |
104232a1795fSJyri Sarha 		       FLD_VAL(hbp - 1, 31, 20));
104332a1795fSJyri Sarha 
104432a1795fSJyri Sarha 	dispc_vp_write(dispc, hw_videoport, DISPC_VP_TIMING_V,
104532a1795fSJyri Sarha 		       FLD_VAL(vsw - 1, 7, 0) |
104632a1795fSJyri Sarha 		       FLD_VAL(vfp, 19, 8) |
104732a1795fSJyri Sarha 		       FLD_VAL(vbp, 31, 20));
104832a1795fSJyri Sarha 
104932a1795fSJyri Sarha 	ivs = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
105032a1795fSJyri Sarha 
105132a1795fSJyri Sarha 	ihs = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
105232a1795fSJyri Sarha 
105332a1795fSJyri Sarha 	ieo = !!(tstate->bus_flags & DRM_BUS_FLAG_DE_LOW);
105432a1795fSJyri Sarha 
105531a5f441SSam Ravnborg 	ipc = !!(tstate->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE);
105632a1795fSJyri Sarha 
105732a1795fSJyri Sarha 	/* always use the 'rf' setting */
105832a1795fSJyri Sarha 	onoff = true;
105932a1795fSJyri Sarha 
106031a5f441SSam Ravnborg 	rf = !!(tstate->bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE);
106132a1795fSJyri Sarha 
106232a1795fSJyri Sarha 	/* always use aligned syncs */
106332a1795fSJyri Sarha 	align = true;
106432a1795fSJyri Sarha 
106532a1795fSJyri Sarha 	/* always use DE_HIGH for OLDI */
106632a1795fSJyri Sarha 	if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI)
106732a1795fSJyri Sarha 		ieo = false;
106832a1795fSJyri Sarha 
106932a1795fSJyri Sarha 	dispc_vp_write(dispc, hw_videoport, DISPC_VP_POL_FREQ,
107032a1795fSJyri Sarha 		       FLD_VAL(align, 18, 18) |
107132a1795fSJyri Sarha 		       FLD_VAL(onoff, 17, 17) |
107232a1795fSJyri Sarha 		       FLD_VAL(rf, 16, 16) |
107332a1795fSJyri Sarha 		       FLD_VAL(ieo, 15, 15) |
107432a1795fSJyri Sarha 		       FLD_VAL(ipc, 14, 14) |
107532a1795fSJyri Sarha 		       FLD_VAL(ihs, 13, 13) |
107632a1795fSJyri Sarha 		       FLD_VAL(ivs, 12, 12));
107732a1795fSJyri Sarha 
107832a1795fSJyri Sarha 	dispc_vp_write(dispc, hw_videoport, DISPC_VP_SIZE_SCREEN,
107932a1795fSJyri Sarha 		       FLD_VAL(mode->hdisplay - 1, 11, 0) |
108032a1795fSJyri Sarha 		       FLD_VAL(mode->vdisplay - 1, 27, 16));
108132a1795fSJyri Sarha 
108232a1795fSJyri Sarha 	VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, 1, 0, 0);
108332a1795fSJyri Sarha }
108432a1795fSJyri Sarha 
dispc_vp_disable(struct dispc_device * dispc,u32 hw_videoport)108532a1795fSJyri Sarha void dispc_vp_disable(struct dispc_device *dispc, u32 hw_videoport)
108632a1795fSJyri Sarha {
108732a1795fSJyri Sarha 	VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, 0, 0, 0);
108832a1795fSJyri Sarha }
108932a1795fSJyri Sarha 
dispc_vp_unprepare(struct dispc_device * dispc,u32 hw_videoport)109032a1795fSJyri Sarha void dispc_vp_unprepare(struct dispc_device *dispc, u32 hw_videoport)
109132a1795fSJyri Sarha {
109232a1795fSJyri Sarha 	if (dispc->feat->vp_bus_type[hw_videoport] == DISPC_VP_OLDI) {
109332a1795fSJyri Sarha 		dispc_vp_write(dispc, hw_videoport, DISPC_VP_DSS_OLDI_CFG, 0);
109432a1795fSJyri Sarha 
109532a1795fSJyri Sarha 		dispc_oldi_tx_power(dispc, false);
109632a1795fSJyri Sarha 	}
109732a1795fSJyri Sarha }
109832a1795fSJyri Sarha 
dispc_vp_go_busy(struct dispc_device * dispc,u32 hw_videoport)109932a1795fSJyri Sarha bool dispc_vp_go_busy(struct dispc_device *dispc, u32 hw_videoport)
110032a1795fSJyri Sarha {
110132a1795fSJyri Sarha 	return VP_REG_GET(dispc, hw_videoport, DISPC_VP_CONTROL, 5, 5);
110232a1795fSJyri Sarha }
110332a1795fSJyri Sarha 
dispc_vp_go(struct dispc_device * dispc,u32 hw_videoport)110432a1795fSJyri Sarha void dispc_vp_go(struct dispc_device *dispc, u32 hw_videoport)
110532a1795fSJyri Sarha {
110632a1795fSJyri Sarha 	WARN_ON(VP_REG_GET(dispc, hw_videoport, DISPC_VP_CONTROL, 5, 5));
110732a1795fSJyri Sarha 	VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONTROL, 1, 5, 5);
110832a1795fSJyri Sarha }
110932a1795fSJyri Sarha 
111032a1795fSJyri Sarha enum c8_to_c12_mode { C8_TO_C12_REPLICATE, C8_TO_C12_MAX, C8_TO_C12_MIN };
111132a1795fSJyri Sarha 
c8_to_c12(u8 c8,enum c8_to_c12_mode mode)111232a1795fSJyri Sarha static u16 c8_to_c12(u8 c8, enum c8_to_c12_mode mode)
111332a1795fSJyri Sarha {
111432a1795fSJyri Sarha 	u16 c12;
111532a1795fSJyri Sarha 
111632a1795fSJyri Sarha 	c12 = c8 << 4;
111732a1795fSJyri Sarha 
111832a1795fSJyri Sarha 	switch (mode) {
111932a1795fSJyri Sarha 	case C8_TO_C12_REPLICATE:
112032a1795fSJyri Sarha 		/* Copy c8 4 MSB to 4 LSB for full scale c12 */
112132a1795fSJyri Sarha 		c12 |= c8 >> 4;
112232a1795fSJyri Sarha 		break;
112332a1795fSJyri Sarha 	case C8_TO_C12_MAX:
112432a1795fSJyri Sarha 		c12 |= 0xF;
112532a1795fSJyri Sarha 		break;
112632a1795fSJyri Sarha 	default:
112732a1795fSJyri Sarha 	case C8_TO_C12_MIN:
112832a1795fSJyri Sarha 		break;
112932a1795fSJyri Sarha 	}
113032a1795fSJyri Sarha 
113132a1795fSJyri Sarha 	return c12;
113232a1795fSJyri Sarha }
113332a1795fSJyri Sarha 
argb8888_to_argb12121212(u32 argb8888,enum c8_to_c12_mode m)113432a1795fSJyri Sarha static u64 argb8888_to_argb12121212(u32 argb8888, enum c8_to_c12_mode m)
113532a1795fSJyri Sarha {
113632a1795fSJyri Sarha 	u8 a, r, g, b;
113732a1795fSJyri Sarha 	u64 v;
113832a1795fSJyri Sarha 
113932a1795fSJyri Sarha 	a = (argb8888 >> 24) & 0xff;
114032a1795fSJyri Sarha 	r = (argb8888 >> 16) & 0xff;
114132a1795fSJyri Sarha 	g = (argb8888 >> 8) & 0xff;
114232a1795fSJyri Sarha 	b = (argb8888 >> 0) & 0xff;
114332a1795fSJyri Sarha 
114432a1795fSJyri Sarha 	v = ((u64)c8_to_c12(a, m) << 36) | ((u64)c8_to_c12(r, m) << 24) |
114532a1795fSJyri Sarha 		((u64)c8_to_c12(g, m) << 12) | (u64)c8_to_c12(b, m);
114632a1795fSJyri Sarha 
114732a1795fSJyri Sarha 	return v;
114832a1795fSJyri Sarha }
114932a1795fSJyri Sarha 
dispc_vp_set_default_color(struct dispc_device * dispc,u32 hw_videoport,u32 default_color)115032a1795fSJyri Sarha static void dispc_vp_set_default_color(struct dispc_device *dispc,
115132a1795fSJyri Sarha 				       u32 hw_videoport, u32 default_color)
115232a1795fSJyri Sarha {
115332a1795fSJyri Sarha 	u64 v;
115432a1795fSJyri Sarha 
115532a1795fSJyri Sarha 	v = argb8888_to_argb12121212(default_color, C8_TO_C12_REPLICATE);
115632a1795fSJyri Sarha 
115732a1795fSJyri Sarha 	dispc_ovr_write(dispc, hw_videoport,
115832a1795fSJyri Sarha 			DISPC_OVR_DEFAULT_COLOR, v & 0xffffffff);
115932a1795fSJyri Sarha 	dispc_ovr_write(dispc, hw_videoport,
116032a1795fSJyri Sarha 			DISPC_OVR_DEFAULT_COLOR2, (v >> 32) & 0xffff);
116132a1795fSJyri Sarha }
116232a1795fSJyri Sarha 
dispc_vp_mode_valid(struct dispc_device * dispc,u32 hw_videoport,const struct drm_display_mode * mode)116332a1795fSJyri Sarha enum drm_mode_status dispc_vp_mode_valid(struct dispc_device *dispc,
116432a1795fSJyri Sarha 					 u32 hw_videoport,
116532a1795fSJyri Sarha 					 const struct drm_display_mode *mode)
116632a1795fSJyri Sarha {
116732a1795fSJyri Sarha 	u32 hsw, hfp, hbp, vsw, vfp, vbp;
116832a1795fSJyri Sarha 	enum dispc_vp_bus_type bus_type;
116932a1795fSJyri Sarha 	int max_pclk;
117032a1795fSJyri Sarha 
117132a1795fSJyri Sarha 	bus_type = dispc->feat->vp_bus_type[hw_videoport];
117232a1795fSJyri Sarha 
117332a1795fSJyri Sarha 	max_pclk = dispc->feat->max_pclk_khz[bus_type];
117432a1795fSJyri Sarha 
117532a1795fSJyri Sarha 	if (WARN_ON(max_pclk == 0))
117632a1795fSJyri Sarha 		return MODE_BAD;
117732a1795fSJyri Sarha 
117832a1795fSJyri Sarha 	if (mode->clock < dispc->feat->min_pclk_khz)
117932a1795fSJyri Sarha 		return MODE_CLOCK_LOW;
118032a1795fSJyri Sarha 
118132a1795fSJyri Sarha 	if (mode->clock > max_pclk)
118232a1795fSJyri Sarha 		return MODE_CLOCK_HIGH;
118332a1795fSJyri Sarha 
118432a1795fSJyri Sarha 	if (mode->hdisplay > 4096)
118532a1795fSJyri Sarha 		return MODE_BAD;
118632a1795fSJyri Sarha 
118732a1795fSJyri Sarha 	if (mode->vdisplay > 4096)
118832a1795fSJyri Sarha 		return MODE_BAD;
118932a1795fSJyri Sarha 
119032a1795fSJyri Sarha 	/* TODO: add interlace support */
119132a1795fSJyri Sarha 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
119232a1795fSJyri Sarha 		return MODE_NO_INTERLACE;
119332a1795fSJyri Sarha 
119432a1795fSJyri Sarha 	/*
119532a1795fSJyri Sarha 	 * Enforce the output width is divisible by 2. Actually this
119632a1795fSJyri Sarha 	 * is only needed in following cases:
119732a1795fSJyri Sarha 	 * - YUV output selected (BT656, BT1120)
119832a1795fSJyri Sarha 	 * - Dithering enabled
119932a1795fSJyri Sarha 	 * - TDM with TDMCycleFormat == 3
120032a1795fSJyri Sarha 	 * But for simplicity we enforce that always.
120132a1795fSJyri Sarha 	 */
120232a1795fSJyri Sarha 	if ((mode->hdisplay % 2) != 0)
120332a1795fSJyri Sarha 		return MODE_BAD_HVALUE;
120432a1795fSJyri Sarha 
120532a1795fSJyri Sarha 	hfp = mode->hsync_start - mode->hdisplay;
120632a1795fSJyri Sarha 	hsw = mode->hsync_end - mode->hsync_start;
120732a1795fSJyri Sarha 	hbp = mode->htotal - mode->hsync_end;
120832a1795fSJyri Sarha 
120932a1795fSJyri Sarha 	vfp = mode->vsync_start - mode->vdisplay;
121032a1795fSJyri Sarha 	vsw = mode->vsync_end - mode->vsync_start;
121132a1795fSJyri Sarha 	vbp = mode->vtotal - mode->vsync_end;
121232a1795fSJyri Sarha 
121332a1795fSJyri Sarha 	if (hsw < 1 || hsw > 256 ||
121432a1795fSJyri Sarha 	    hfp < 1 || hfp > 4096 ||
121532a1795fSJyri Sarha 	    hbp < 1 || hbp > 4096)
121632a1795fSJyri Sarha 		return MODE_BAD_HVALUE;
121732a1795fSJyri Sarha 
121832a1795fSJyri Sarha 	if (vsw < 1 || vsw > 256 ||
121932a1795fSJyri Sarha 	    vfp > 4095 || vbp > 4095)
122032a1795fSJyri Sarha 		return MODE_BAD_VVALUE;
122132a1795fSJyri Sarha 
122232a1795fSJyri Sarha 	if (dispc->memory_bandwidth_limit) {
122332a1795fSJyri Sarha 		const unsigned int bpp = 4;
122432a1795fSJyri Sarha 		u64 bandwidth;
122532a1795fSJyri Sarha 
122632a1795fSJyri Sarha 		bandwidth = 1000 * mode->clock;
122732a1795fSJyri Sarha 		bandwidth = bandwidth * mode->hdisplay * mode->vdisplay * bpp;
122832a1795fSJyri Sarha 		bandwidth = div_u64(bandwidth, mode->htotal * mode->vtotal);
122932a1795fSJyri Sarha 
123032a1795fSJyri Sarha 		if (dispc->memory_bandwidth_limit < bandwidth)
123132a1795fSJyri Sarha 			return MODE_BAD;
123232a1795fSJyri Sarha 	}
123332a1795fSJyri Sarha 
123432a1795fSJyri Sarha 	return MODE_OK;
123532a1795fSJyri Sarha }
123632a1795fSJyri Sarha 
dispc_vp_enable_clk(struct dispc_device * dispc,u32 hw_videoport)123732a1795fSJyri Sarha int dispc_vp_enable_clk(struct dispc_device *dispc, u32 hw_videoport)
123832a1795fSJyri Sarha {
123932a1795fSJyri Sarha 	int ret = clk_prepare_enable(dispc->vp_clk[hw_videoport]);
124032a1795fSJyri Sarha 
124132a1795fSJyri Sarha 	if (ret)
124232a1795fSJyri Sarha 		dev_err(dispc->dev, "%s: enabling clk failed: %d\n", __func__,
124332a1795fSJyri Sarha 			ret);
124432a1795fSJyri Sarha 
124532a1795fSJyri Sarha 	return ret;
124632a1795fSJyri Sarha }
124732a1795fSJyri Sarha 
dispc_vp_disable_clk(struct dispc_device * dispc,u32 hw_videoport)124832a1795fSJyri Sarha void dispc_vp_disable_clk(struct dispc_device *dispc, u32 hw_videoport)
124932a1795fSJyri Sarha {
125032a1795fSJyri Sarha 	clk_disable_unprepare(dispc->vp_clk[hw_videoport]);
125132a1795fSJyri Sarha }
125232a1795fSJyri Sarha 
125332a1795fSJyri Sarha /*
125432a1795fSJyri Sarha  * Calculate the percentage difference between the requested pixel clock rate
125532a1795fSJyri Sarha  * and the effective rate resulting from calculating the clock divider value.
125632a1795fSJyri Sarha  */
125732a1795fSJyri Sarha static
dispc_pclk_diff(unsigned long rate,unsigned long real_rate)125832a1795fSJyri Sarha unsigned int dispc_pclk_diff(unsigned long rate, unsigned long real_rate)
125932a1795fSJyri Sarha {
126032a1795fSJyri Sarha 	int r = rate / 100, rr = real_rate / 100;
126132a1795fSJyri Sarha 
126232a1795fSJyri Sarha 	return (unsigned int)(abs(((rr - r) * 100) / r));
126332a1795fSJyri Sarha }
126432a1795fSJyri Sarha 
dispc_vp_set_clk_rate(struct dispc_device * dispc,u32 hw_videoport,unsigned long rate)126532a1795fSJyri Sarha int dispc_vp_set_clk_rate(struct dispc_device *dispc, u32 hw_videoport,
126632a1795fSJyri Sarha 			  unsigned long rate)
126732a1795fSJyri Sarha {
126832a1795fSJyri Sarha 	int r;
126932a1795fSJyri Sarha 	unsigned long new_rate;
127032a1795fSJyri Sarha 
127132a1795fSJyri Sarha 	r = clk_set_rate(dispc->vp_clk[hw_videoport], rate);
127232a1795fSJyri Sarha 	if (r) {
127332a1795fSJyri Sarha 		dev_err(dispc->dev, "vp%d: failed to set clk rate to %lu\n",
127432a1795fSJyri Sarha 			hw_videoport, rate);
127532a1795fSJyri Sarha 		return r;
127632a1795fSJyri Sarha 	}
127732a1795fSJyri Sarha 
127832a1795fSJyri Sarha 	new_rate = clk_get_rate(dispc->vp_clk[hw_videoport]);
127932a1795fSJyri Sarha 
128032a1795fSJyri Sarha 	if (dispc_pclk_diff(rate, new_rate) > 5)
128132a1795fSJyri Sarha 		dev_warn(dispc->dev,
1282652f67fdSColin Ian King 			 "vp%d: Clock rate %lu differs over 5%% from requested %lu\n",
128332a1795fSJyri Sarha 			 hw_videoport, new_rate, rate);
128432a1795fSJyri Sarha 
128532a1795fSJyri Sarha 	dev_dbg(dispc->dev, "vp%d: new rate %lu Hz (requested %lu Hz)\n",
128632a1795fSJyri Sarha 		hw_videoport, clk_get_rate(dispc->vp_clk[hw_videoport]), rate);
128732a1795fSJyri Sarha 
128832a1795fSJyri Sarha 	return 0;
128932a1795fSJyri Sarha }
129032a1795fSJyri Sarha 
129132a1795fSJyri Sarha /* OVR */
dispc_k2g_ovr_set_plane(struct dispc_device * dispc,u32 hw_plane,u32 hw_videoport,u32 x,u32 y,u32 layer)129232a1795fSJyri Sarha static void dispc_k2g_ovr_set_plane(struct dispc_device *dispc,
129332a1795fSJyri Sarha 				    u32 hw_plane, u32 hw_videoport,
1294b33b5474SJyri Sarha 				    u32 x, u32 y, u32 layer)
129532a1795fSJyri Sarha {
129632a1795fSJyri Sarha 	/* On k2g there is only one plane and no need for ovr */
129732a1795fSJyri Sarha 	dispc_vid_write(dispc, hw_plane, DISPC_VID_K2G_POSITION,
129832a1795fSJyri Sarha 			x | (y << 16));
129932a1795fSJyri Sarha }
130032a1795fSJyri Sarha 
dispc_am65x_ovr_set_plane(struct dispc_device * dispc,u32 hw_plane,u32 hw_videoport,u32 x,u32 y,u32 layer)130132a1795fSJyri Sarha static void dispc_am65x_ovr_set_plane(struct dispc_device *dispc,
130232a1795fSJyri Sarha 				      u32 hw_plane, u32 hw_videoport,
1303b33b5474SJyri Sarha 				      u32 x, u32 y, u32 layer)
130432a1795fSJyri Sarha {
1305b33b5474SJyri Sarha 	OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer),
130632a1795fSJyri Sarha 			hw_plane, 4, 1);
1307b33b5474SJyri Sarha 	OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer),
130832a1795fSJyri Sarha 			x, 17, 6);
1309b33b5474SJyri Sarha 	OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer),
131032a1795fSJyri Sarha 			y, 30, 19);
131132a1795fSJyri Sarha }
131232a1795fSJyri Sarha 
dispc_j721e_ovr_set_plane(struct dispc_device * dispc,u32 hw_plane,u32 hw_videoport,u32 x,u32 y,u32 layer)131332a1795fSJyri Sarha static void dispc_j721e_ovr_set_plane(struct dispc_device *dispc,
131432a1795fSJyri Sarha 				      u32 hw_plane, u32 hw_videoport,
1315b33b5474SJyri Sarha 				      u32 x, u32 y, u32 layer)
131632a1795fSJyri Sarha {
1317b33b5474SJyri Sarha 	OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer),
131832a1795fSJyri Sarha 			hw_plane, 4, 1);
1319b33b5474SJyri Sarha 	OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES2(layer),
132032a1795fSJyri Sarha 			x, 13, 0);
1321b33b5474SJyri Sarha 	OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES2(layer),
132232a1795fSJyri Sarha 			y, 29, 16);
132332a1795fSJyri Sarha }
132432a1795fSJyri Sarha 
dispc_ovr_set_plane(struct dispc_device * dispc,u32 hw_plane,u32 hw_videoport,u32 x,u32 y,u32 layer)1325b33b5474SJyri Sarha void dispc_ovr_set_plane(struct dispc_device *dispc, u32 hw_plane,
1326b33b5474SJyri Sarha 			 u32 hw_videoport, u32 x, u32 y, u32 layer)
132732a1795fSJyri Sarha {
132832a1795fSJyri Sarha 	switch (dispc->feat->subrev) {
132932a1795fSJyri Sarha 	case DISPC_K2G:
133032a1795fSJyri Sarha 		dispc_k2g_ovr_set_plane(dispc, hw_plane, hw_videoport,
1331b33b5474SJyri Sarha 					x, y, layer);
133232a1795fSJyri Sarha 		break;
1333ad2ac9dcSAradhya Bhatia 	case DISPC_AM625:
133432a1795fSJyri Sarha 	case DISPC_AM65X:
133532a1795fSJyri Sarha 		dispc_am65x_ovr_set_plane(dispc, hw_plane, hw_videoport,
1336b33b5474SJyri Sarha 					  x, y, layer);
133732a1795fSJyri Sarha 		break;
133832a1795fSJyri Sarha 	case DISPC_J721E:
133932a1795fSJyri Sarha 		dispc_j721e_ovr_set_plane(dispc, hw_plane, hw_videoport,
1340b33b5474SJyri Sarha 					  x, y, layer);
134132a1795fSJyri Sarha 		break;
134232a1795fSJyri Sarha 	default:
134332a1795fSJyri Sarha 		WARN_ON(1);
134432a1795fSJyri Sarha 		break;
134532a1795fSJyri Sarha 	}
134632a1795fSJyri Sarha }
134732a1795fSJyri Sarha 
dispc_ovr_enable_layer(struct dispc_device * dispc,u32 hw_videoport,u32 layer,bool enable)1348b33b5474SJyri Sarha void dispc_ovr_enable_layer(struct dispc_device *dispc,
1349b33b5474SJyri Sarha 			    u32 hw_videoport, u32 layer, bool enable)
135032a1795fSJyri Sarha {
1351b33b5474SJyri Sarha 	if (dispc->feat->subrev == DISPC_K2G)
1352b33b5474SJyri Sarha 		return;
1353b33b5474SJyri Sarha 
1354b33b5474SJyri Sarha 	OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer),
135532a1795fSJyri Sarha 			!!enable, 0, 0);
135632a1795fSJyri Sarha }
135732a1795fSJyri Sarha 
135832a1795fSJyri Sarha /* CSC */
135932a1795fSJyri Sarha enum csc_ctm {
136032a1795fSJyri Sarha 	CSC_RR, CSC_RG, CSC_RB,
136132a1795fSJyri Sarha 	CSC_GR, CSC_GG, CSC_GB,
136232a1795fSJyri Sarha 	CSC_BR, CSC_BG, CSC_BB,
136332a1795fSJyri Sarha };
136432a1795fSJyri Sarha 
136532a1795fSJyri Sarha enum csc_yuv2rgb {
136632a1795fSJyri Sarha 	CSC_RY, CSC_RCB, CSC_RCR,
136732a1795fSJyri Sarha 	CSC_GY, CSC_GCB, CSC_GCR,
136832a1795fSJyri Sarha 	CSC_BY, CSC_BCB, CSC_BCR,
136932a1795fSJyri Sarha };
137032a1795fSJyri Sarha 
137132a1795fSJyri Sarha enum csc_rgb2yuv {
137232a1795fSJyri Sarha 	CSC_YR,  CSC_YG,  CSC_YB,
137332a1795fSJyri Sarha 	CSC_CBR, CSC_CBG, CSC_CBB,
137432a1795fSJyri Sarha 	CSC_CRR, CSC_CRG, CSC_CRB,
137532a1795fSJyri Sarha };
137632a1795fSJyri Sarha 
137732a1795fSJyri Sarha struct dispc_csc_coef {
137832a1795fSJyri Sarha 	void (*to_regval)(const struct dispc_csc_coef *csc, u32 *regval);
137932a1795fSJyri Sarha 	int m[9];
138032a1795fSJyri Sarha 	int preoffset[3];
138132a1795fSJyri Sarha 	int postoffset[3];
138232a1795fSJyri Sarha 	enum { CLIP_LIMITED_RANGE = 0, CLIP_FULL_RANGE = 1, } cliping;
138332a1795fSJyri Sarha 	const char *name;
138432a1795fSJyri Sarha };
138532a1795fSJyri Sarha 
138632a1795fSJyri Sarha #define DISPC_CSC_REGVAL_LEN 8
138732a1795fSJyri Sarha 
138832a1795fSJyri Sarha static
dispc_csc_offset_regval(const struct dispc_csc_coef * csc,u32 * regval)138932a1795fSJyri Sarha void dispc_csc_offset_regval(const struct dispc_csc_coef *csc, u32 *regval)
139032a1795fSJyri Sarha {
139132a1795fSJyri Sarha #define OVAL(x, y) (FLD_VAL(x, 15, 3) | FLD_VAL(y, 31, 19))
139232a1795fSJyri Sarha 	regval[5] = OVAL(csc->preoffset[0], csc->preoffset[1]);
139332a1795fSJyri Sarha 	regval[6] = OVAL(csc->preoffset[2], csc->postoffset[0]);
139432a1795fSJyri Sarha 	regval[7] = OVAL(csc->postoffset[1], csc->postoffset[2]);
139532a1795fSJyri Sarha #undef OVAL
139632a1795fSJyri Sarha }
139732a1795fSJyri Sarha 
139832a1795fSJyri Sarha #define CVAL(x, y) (FLD_VAL(x, 10, 0) | FLD_VAL(y, 26, 16))
139932a1795fSJyri Sarha static
dispc_csc_yuv2rgb_regval(const struct dispc_csc_coef * csc,u32 * regval)140032a1795fSJyri Sarha void dispc_csc_yuv2rgb_regval(const struct dispc_csc_coef *csc, u32 *regval)
140132a1795fSJyri Sarha {
140232a1795fSJyri Sarha 	regval[0] = CVAL(csc->m[CSC_RY], csc->m[CSC_RCR]);
140332a1795fSJyri Sarha 	regval[1] = CVAL(csc->m[CSC_RCB], csc->m[CSC_GY]);
140432a1795fSJyri Sarha 	regval[2] = CVAL(csc->m[CSC_GCR], csc->m[CSC_GCB]);
140532a1795fSJyri Sarha 	regval[3] = CVAL(csc->m[CSC_BY], csc->m[CSC_BCR]);
140632a1795fSJyri Sarha 	regval[4] = CVAL(csc->m[CSC_BCB], 0);
140732a1795fSJyri Sarha 
140832a1795fSJyri Sarha 	dispc_csc_offset_regval(csc, regval);
140932a1795fSJyri Sarha }
141032a1795fSJyri Sarha 
141132a1795fSJyri Sarha __maybe_unused static
dispc_csc_rgb2yuv_regval(const struct dispc_csc_coef * csc,u32 * regval)141232a1795fSJyri Sarha void dispc_csc_rgb2yuv_regval(const struct dispc_csc_coef *csc, u32 *regval)
141332a1795fSJyri Sarha {
141432a1795fSJyri Sarha 	regval[0] = CVAL(csc->m[CSC_YR], csc->m[CSC_YG]);
141532a1795fSJyri Sarha 	regval[1] = CVAL(csc->m[CSC_YB], csc->m[CSC_CRR]);
141632a1795fSJyri Sarha 	regval[2] = CVAL(csc->m[CSC_CRG], csc->m[CSC_CRB]);
141732a1795fSJyri Sarha 	regval[3] = CVAL(csc->m[CSC_CBR], csc->m[CSC_CBG]);
141832a1795fSJyri Sarha 	regval[4] = CVAL(csc->m[CSC_CBB], 0);
141932a1795fSJyri Sarha 
142032a1795fSJyri Sarha 	dispc_csc_offset_regval(csc, regval);
142132a1795fSJyri Sarha }
142232a1795fSJyri Sarha 
dispc_csc_cpr_regval(const struct dispc_csc_coef * csc,u32 * regval)142332a1795fSJyri Sarha static void dispc_csc_cpr_regval(const struct dispc_csc_coef *csc,
142432a1795fSJyri Sarha 				 u32 *regval)
142532a1795fSJyri Sarha {
142632a1795fSJyri Sarha 	regval[0] = CVAL(csc->m[CSC_RR], csc->m[CSC_RG]);
142732a1795fSJyri Sarha 	regval[1] = CVAL(csc->m[CSC_RB], csc->m[CSC_GR]);
142832a1795fSJyri Sarha 	regval[2] = CVAL(csc->m[CSC_GG], csc->m[CSC_GB]);
142932a1795fSJyri Sarha 	regval[3] = CVAL(csc->m[CSC_BR], csc->m[CSC_BG]);
143032a1795fSJyri Sarha 	regval[4] = CVAL(csc->m[CSC_BB], 0);
143132a1795fSJyri Sarha 
143232a1795fSJyri Sarha 	dispc_csc_offset_regval(csc, regval);
143332a1795fSJyri Sarha }
143432a1795fSJyri Sarha 
143532a1795fSJyri Sarha #undef CVAL
143632a1795fSJyri Sarha 
dispc_k2g_vid_write_csc(struct dispc_device * dispc,u32 hw_plane,const struct dispc_csc_coef * csc)143732a1795fSJyri Sarha static void dispc_k2g_vid_write_csc(struct dispc_device *dispc, u32 hw_plane,
143832a1795fSJyri Sarha 				    const struct dispc_csc_coef *csc)
143932a1795fSJyri Sarha {
144032a1795fSJyri Sarha 	static const u16 dispc_vid_csc_coef_reg[] = {
144132a1795fSJyri Sarha 		DISPC_VID_CSC_COEF(0), DISPC_VID_CSC_COEF(1),
144232a1795fSJyri Sarha 		DISPC_VID_CSC_COEF(2), DISPC_VID_CSC_COEF(3),
144332a1795fSJyri Sarha 		DISPC_VID_CSC_COEF(4), DISPC_VID_CSC_COEF(5),
144432a1795fSJyri Sarha 		DISPC_VID_CSC_COEF(6), /* K2G has no post offset support */
144532a1795fSJyri Sarha 	};
144632a1795fSJyri Sarha 	u32 regval[DISPC_CSC_REGVAL_LEN];
144732a1795fSJyri Sarha 	unsigned int i;
144832a1795fSJyri Sarha 
144932a1795fSJyri Sarha 	csc->to_regval(csc, regval);
145032a1795fSJyri Sarha 
145132a1795fSJyri Sarha 	if (regval[7] != 0)
145232a1795fSJyri Sarha 		dev_warn(dispc->dev, "%s: No post offset support for %s\n",
145332a1795fSJyri Sarha 			 __func__, csc->name);
145432a1795fSJyri Sarha 
145532a1795fSJyri Sarha 	for (i = 0; i < ARRAY_SIZE(dispc_vid_csc_coef_reg); i++)
145632a1795fSJyri Sarha 		dispc_vid_write(dispc, hw_plane, dispc_vid_csc_coef_reg[i],
145732a1795fSJyri Sarha 				regval[i]);
145832a1795fSJyri Sarha }
145932a1795fSJyri Sarha 
dispc_k3_vid_write_csc(struct dispc_device * dispc,u32 hw_plane,const struct dispc_csc_coef * csc)146032a1795fSJyri Sarha static void dispc_k3_vid_write_csc(struct dispc_device *dispc, u32 hw_plane,
146132a1795fSJyri Sarha 				   const struct dispc_csc_coef *csc)
146232a1795fSJyri Sarha {
146332a1795fSJyri Sarha 	static const u16 dispc_vid_csc_coef_reg[DISPC_CSC_REGVAL_LEN] = {
146432a1795fSJyri Sarha 		DISPC_VID_CSC_COEF(0), DISPC_VID_CSC_COEF(1),
146532a1795fSJyri Sarha 		DISPC_VID_CSC_COEF(2), DISPC_VID_CSC_COEF(3),
146632a1795fSJyri Sarha 		DISPC_VID_CSC_COEF(4), DISPC_VID_CSC_COEF(5),
146732a1795fSJyri Sarha 		DISPC_VID_CSC_COEF(6), DISPC_VID_CSC_COEF7,
146832a1795fSJyri Sarha 	};
146932a1795fSJyri Sarha 	u32 regval[DISPC_CSC_REGVAL_LEN];
147032a1795fSJyri Sarha 	unsigned int i;
147132a1795fSJyri Sarha 
147232a1795fSJyri Sarha 	csc->to_regval(csc, regval);
147332a1795fSJyri Sarha 
147432a1795fSJyri Sarha 	for (i = 0; i < ARRAY_SIZE(dispc_vid_csc_coef_reg); i++)
147532a1795fSJyri Sarha 		dispc_vid_write(dispc, hw_plane, dispc_vid_csc_coef_reg[i],
147632a1795fSJyri Sarha 				regval[i]);
147732a1795fSJyri Sarha }
147832a1795fSJyri Sarha 
147932a1795fSJyri Sarha /* YUV -> RGB, ITU-R BT.601, full range */
148032a1795fSJyri Sarha static const struct dispc_csc_coef csc_yuv2rgb_bt601_full = {
148132a1795fSJyri Sarha 	dispc_csc_yuv2rgb_regval,
148232a1795fSJyri Sarha 	{ 256,   0,  358,	/* ry, rcb, rcr |1.000  0.000  1.402|*/
148332a1795fSJyri Sarha 	  256, -88, -182,	/* gy, gcb, gcr |1.000 -0.344 -0.714|*/
148432a1795fSJyri Sarha 	  256, 452,    0, },	/* by, bcb, bcr |1.000  1.772  0.000|*/
148532a1795fSJyri Sarha 	{    0, -2048, -2048, },	/* full range */
148632a1795fSJyri Sarha 	{    0,     0,     0, },
148732a1795fSJyri Sarha 	CLIP_FULL_RANGE,
148832a1795fSJyri Sarha 	"BT.601 Full",
148932a1795fSJyri Sarha };
149032a1795fSJyri Sarha 
149132a1795fSJyri Sarha /* YUV -> RGB, ITU-R BT.601, limited range */
149232a1795fSJyri Sarha static const struct dispc_csc_coef csc_yuv2rgb_bt601_lim = {
149332a1795fSJyri Sarha 	dispc_csc_yuv2rgb_regval,
149432a1795fSJyri Sarha 	{ 298,    0,  409,	/* ry, rcb, rcr |1.164  0.000  1.596|*/
149532a1795fSJyri Sarha 	  298, -100, -208,	/* gy, gcb, gcr |1.164 -0.392 -0.813|*/
149632a1795fSJyri Sarha 	  298,  516,    0, },	/* by, bcb, bcr |1.164  2.017  0.000|*/
149732a1795fSJyri Sarha 	{ -256, -2048, -2048, },	/* limited range */
149832a1795fSJyri Sarha 	{    0,     0,     0, },
149932a1795fSJyri Sarha 	CLIP_FULL_RANGE,
150032a1795fSJyri Sarha 	"BT.601 Limited",
150132a1795fSJyri Sarha };
150232a1795fSJyri Sarha 
150332a1795fSJyri Sarha /* YUV -> RGB, ITU-R BT.709, full range */
150432a1795fSJyri Sarha static const struct dispc_csc_coef csc_yuv2rgb_bt709_full = {
150532a1795fSJyri Sarha 	dispc_csc_yuv2rgb_regval,
150632a1795fSJyri Sarha 	{ 256,	  0,  402,	/* ry, rcb, rcr |1.000	0.000  1.570|*/
150732a1795fSJyri Sarha 	  256,  -48, -120,	/* gy, gcb, gcr |1.000 -0.187 -0.467|*/
150832a1795fSJyri Sarha 	  256,  475,    0, },	/* by, bcb, bcr |1.000	1.856  0.000|*/
150932a1795fSJyri Sarha 	{    0, -2048, -2048, },	/* full range */
151032a1795fSJyri Sarha 	{    0,     0,     0, },
151132a1795fSJyri Sarha 	CLIP_FULL_RANGE,
151232a1795fSJyri Sarha 	"BT.709 Full",
151332a1795fSJyri Sarha };
151432a1795fSJyri Sarha 
151532a1795fSJyri Sarha /* YUV -> RGB, ITU-R BT.709, limited range */
151632a1795fSJyri Sarha static const struct dispc_csc_coef csc_yuv2rgb_bt709_lim = {
151732a1795fSJyri Sarha 	dispc_csc_yuv2rgb_regval,
151832a1795fSJyri Sarha 	{ 298,    0,  459,	/* ry, rcb, rcr |1.164  0.000  1.793|*/
151932a1795fSJyri Sarha 	  298,  -55, -136,	/* gy, gcb, gcr |1.164 -0.213 -0.533|*/
152032a1795fSJyri Sarha 	  298,  541,    0, },	/* by, bcb, bcr |1.164  2.112  0.000|*/
152132a1795fSJyri Sarha 	{ -256, -2048, -2048, },	/* limited range */
152232a1795fSJyri Sarha 	{    0,     0,     0, },
152332a1795fSJyri Sarha 	CLIP_FULL_RANGE,
152432a1795fSJyri Sarha 	"BT.709 Limited",
152532a1795fSJyri Sarha };
152632a1795fSJyri Sarha 
152732a1795fSJyri Sarha static const struct {
152832a1795fSJyri Sarha 	enum drm_color_encoding encoding;
152932a1795fSJyri Sarha 	enum drm_color_range range;
153032a1795fSJyri Sarha 	const struct dispc_csc_coef *csc;
153132a1795fSJyri Sarha } dispc_csc_table[] = {
153232a1795fSJyri Sarha 	{ DRM_COLOR_YCBCR_BT601, DRM_COLOR_YCBCR_FULL_RANGE,
153332a1795fSJyri Sarha 	  &csc_yuv2rgb_bt601_full, },
153432a1795fSJyri Sarha 	{ DRM_COLOR_YCBCR_BT601, DRM_COLOR_YCBCR_LIMITED_RANGE,
153532a1795fSJyri Sarha 	  &csc_yuv2rgb_bt601_lim, },
153632a1795fSJyri Sarha 	{ DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_FULL_RANGE,
153732a1795fSJyri Sarha 	  &csc_yuv2rgb_bt709_full, },
153832a1795fSJyri Sarha 	{ DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE,
153932a1795fSJyri Sarha 	  &csc_yuv2rgb_bt709_lim, },
154032a1795fSJyri Sarha };
154132a1795fSJyri Sarha 
154232a1795fSJyri Sarha static const
dispc_find_csc(enum drm_color_encoding encoding,enum drm_color_range range)154332a1795fSJyri Sarha struct dispc_csc_coef *dispc_find_csc(enum drm_color_encoding encoding,
154432a1795fSJyri Sarha 				      enum drm_color_range range)
154532a1795fSJyri Sarha {
154632a1795fSJyri Sarha 	unsigned int i;
154732a1795fSJyri Sarha 
154832a1795fSJyri Sarha 	for (i = 0; i < ARRAY_SIZE(dispc_csc_table); i++) {
154932a1795fSJyri Sarha 		if (dispc_csc_table[i].encoding == encoding &&
155032a1795fSJyri Sarha 		    dispc_csc_table[i].range == range) {
155132a1795fSJyri Sarha 			return dispc_csc_table[i].csc;
155232a1795fSJyri Sarha 		}
155332a1795fSJyri Sarha 	}
155432a1795fSJyri Sarha 	return NULL;
155532a1795fSJyri Sarha }
155632a1795fSJyri Sarha 
dispc_vid_csc_setup(struct dispc_device * dispc,u32 hw_plane,const struct drm_plane_state * state)155732a1795fSJyri Sarha static void dispc_vid_csc_setup(struct dispc_device *dispc, u32 hw_plane,
155832a1795fSJyri Sarha 				const struct drm_plane_state *state)
155932a1795fSJyri Sarha {
156046cf7d98SYueHaibing 	const struct dispc_csc_coef *coef;
156132a1795fSJyri Sarha 
156232a1795fSJyri Sarha 	coef = dispc_find_csc(state->color_encoding, state->color_range);
156332a1795fSJyri Sarha 	if (!coef) {
156432a1795fSJyri Sarha 		dev_err(dispc->dev, "%s: CSC (%u,%u) not found\n",
156532a1795fSJyri Sarha 			__func__, state->color_encoding, state->color_range);
156632a1795fSJyri Sarha 		return;
156732a1795fSJyri Sarha 	}
156832a1795fSJyri Sarha 
156932a1795fSJyri Sarha 	if (dispc->feat->subrev == DISPC_K2G)
157032a1795fSJyri Sarha 		dispc_k2g_vid_write_csc(dispc, hw_plane, coef);
157132a1795fSJyri Sarha 	else
157232a1795fSJyri Sarha 		dispc_k3_vid_write_csc(dispc, hw_plane, coef);
157332a1795fSJyri Sarha }
157432a1795fSJyri Sarha 
dispc_vid_csc_enable(struct dispc_device * dispc,u32 hw_plane,bool enable)157532a1795fSJyri Sarha static void dispc_vid_csc_enable(struct dispc_device *dispc, u32 hw_plane,
157632a1795fSJyri Sarha 				 bool enable)
157732a1795fSJyri Sarha {
157832a1795fSJyri Sarha 	VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, !!enable, 9, 9);
157932a1795fSJyri Sarha }
158032a1795fSJyri Sarha 
158132a1795fSJyri Sarha /* SCALER */
158232a1795fSJyri Sarha 
dispc_calc_fir_inc(u32 in,u32 out)158332a1795fSJyri Sarha static u32 dispc_calc_fir_inc(u32 in, u32 out)
158432a1795fSJyri Sarha {
158532a1795fSJyri Sarha 	return (u32)div_u64(0x200000ull * in, out);
158632a1795fSJyri Sarha }
158732a1795fSJyri Sarha 
158832a1795fSJyri Sarha enum dispc_vid_fir_coef_set {
158932a1795fSJyri Sarha 	DISPC_VID_FIR_COEF_HORIZ,
159032a1795fSJyri Sarha 	DISPC_VID_FIR_COEF_HORIZ_UV,
159132a1795fSJyri Sarha 	DISPC_VID_FIR_COEF_VERT,
159232a1795fSJyri Sarha 	DISPC_VID_FIR_COEF_VERT_UV,
159332a1795fSJyri Sarha };
159432a1795fSJyri Sarha 
dispc_vid_write_fir_coefs(struct dispc_device * dispc,u32 hw_plane,enum dispc_vid_fir_coef_set coef_set,const struct tidss_scale_coefs * coefs)159532a1795fSJyri Sarha static void dispc_vid_write_fir_coefs(struct dispc_device *dispc,
159632a1795fSJyri Sarha 				      u32 hw_plane,
159732a1795fSJyri Sarha 				      enum dispc_vid_fir_coef_set coef_set,
159832a1795fSJyri Sarha 				      const struct tidss_scale_coefs *coefs)
159932a1795fSJyri Sarha {
160032a1795fSJyri Sarha 	static const u16 c0_regs[] = {
160132a1795fSJyri Sarha 		[DISPC_VID_FIR_COEF_HORIZ] = DISPC_VID_FIR_COEFS_H0,
160232a1795fSJyri Sarha 		[DISPC_VID_FIR_COEF_HORIZ_UV] = DISPC_VID_FIR_COEFS_H0_C,
160332a1795fSJyri Sarha 		[DISPC_VID_FIR_COEF_VERT] = DISPC_VID_FIR_COEFS_V0,
160432a1795fSJyri Sarha 		[DISPC_VID_FIR_COEF_VERT_UV] = DISPC_VID_FIR_COEFS_V0_C,
160532a1795fSJyri Sarha 	};
160632a1795fSJyri Sarha 
160732a1795fSJyri Sarha 	static const u16 c12_regs[] = {
160832a1795fSJyri Sarha 		[DISPC_VID_FIR_COEF_HORIZ] = DISPC_VID_FIR_COEFS_H12,
160932a1795fSJyri Sarha 		[DISPC_VID_FIR_COEF_HORIZ_UV] = DISPC_VID_FIR_COEFS_H12_C,
161032a1795fSJyri Sarha 		[DISPC_VID_FIR_COEF_VERT] = DISPC_VID_FIR_COEFS_V12,
161132a1795fSJyri Sarha 		[DISPC_VID_FIR_COEF_VERT_UV] = DISPC_VID_FIR_COEFS_V12_C,
161232a1795fSJyri Sarha 	};
161332a1795fSJyri Sarha 
161432a1795fSJyri Sarha 	const u16 c0_base = c0_regs[coef_set];
161532a1795fSJyri Sarha 	const u16 c12_base = c12_regs[coef_set];
161632a1795fSJyri Sarha 	int phase;
161732a1795fSJyri Sarha 
161832a1795fSJyri Sarha 	if (!coefs) {
161932a1795fSJyri Sarha 		dev_err(dispc->dev, "%s: No coefficients given.\n", __func__);
162032a1795fSJyri Sarha 		return;
162132a1795fSJyri Sarha 	}
162232a1795fSJyri Sarha 
162332a1795fSJyri Sarha 	for (phase = 0; phase <= 8; ++phase) {
162432a1795fSJyri Sarha 		u16 reg = c0_base + phase * 4;
162532a1795fSJyri Sarha 		u16 c0 = coefs->c0[phase];
162632a1795fSJyri Sarha 
162732a1795fSJyri Sarha 		dispc_vid_write(dispc, hw_plane, reg, c0);
162832a1795fSJyri Sarha 	}
162932a1795fSJyri Sarha 
163032a1795fSJyri Sarha 	for (phase = 0; phase <= 15; ++phase) {
163132a1795fSJyri Sarha 		u16 reg = c12_base + phase * 4;
163232a1795fSJyri Sarha 		s16 c1, c2;
163332a1795fSJyri Sarha 		u32 c12;
163432a1795fSJyri Sarha 
163532a1795fSJyri Sarha 		c1 = coefs->c1[phase];
163632a1795fSJyri Sarha 		c2 = coefs->c2[phase];
163732a1795fSJyri Sarha 		c12 = FLD_VAL(c1, 19, 10) | FLD_VAL(c2, 29, 20);
163832a1795fSJyri Sarha 
163932a1795fSJyri Sarha 		dispc_vid_write(dispc, hw_plane, reg, c12);
164032a1795fSJyri Sarha 	}
164132a1795fSJyri Sarha }
164232a1795fSJyri Sarha 
dispc_fourcc_is_yuv(u32 fourcc)164332a1795fSJyri Sarha static bool dispc_fourcc_is_yuv(u32 fourcc)
164432a1795fSJyri Sarha {
164532a1795fSJyri Sarha 	switch (fourcc) {
164632a1795fSJyri Sarha 	case DRM_FORMAT_YUYV:
164732a1795fSJyri Sarha 	case DRM_FORMAT_UYVY:
164832a1795fSJyri Sarha 	case DRM_FORMAT_NV12:
164932a1795fSJyri Sarha 		return true;
165032a1795fSJyri Sarha 	default:
165132a1795fSJyri Sarha 		return false;
165232a1795fSJyri Sarha 	}
165332a1795fSJyri Sarha }
165432a1795fSJyri Sarha 
165532a1795fSJyri Sarha struct dispc_scaling_params {
165632a1795fSJyri Sarha 	int xinc, yinc;
165732a1795fSJyri Sarha 	u32 in_w, in_h, in_w_uv, in_h_uv;
165832a1795fSJyri Sarha 	u32 fir_xinc, fir_yinc, fir_xinc_uv, fir_yinc_uv;
165932a1795fSJyri Sarha 	bool scale_x, scale_y;
166032a1795fSJyri Sarha 	const struct tidss_scale_coefs *xcoef, *ycoef, *xcoef_uv, *ycoef_uv;
166132a1795fSJyri Sarha 	bool five_taps;
166232a1795fSJyri Sarha };
166332a1795fSJyri Sarha 
dispc_vid_calc_scaling(struct dispc_device * dispc,const struct drm_plane_state * state,struct dispc_scaling_params * sp,bool lite_plane)166432a1795fSJyri Sarha static int dispc_vid_calc_scaling(struct dispc_device *dispc,
166532a1795fSJyri Sarha 				  const struct drm_plane_state *state,
166632a1795fSJyri Sarha 				  struct dispc_scaling_params *sp,
166732a1795fSJyri Sarha 				  bool lite_plane)
166832a1795fSJyri Sarha {
166932a1795fSJyri Sarha 	const struct dispc_features_scaling *f = &dispc->feat->scaling;
167032a1795fSJyri Sarha 	u32 fourcc = state->fb->format->format;
167132a1795fSJyri Sarha 	u32 in_width_max_5tap = f->in_width_max_5tap_rgb;
167232a1795fSJyri Sarha 	u32 in_width_max_3tap = f->in_width_max_3tap_rgb;
167332a1795fSJyri Sarha 	u32 downscale_limit;
167432a1795fSJyri Sarha 	u32 in_width_max;
167532a1795fSJyri Sarha 
167632a1795fSJyri Sarha 	memset(sp, 0, sizeof(*sp));
167732a1795fSJyri Sarha 	sp->xinc = 1;
167832a1795fSJyri Sarha 	sp->yinc = 1;
167932a1795fSJyri Sarha 	sp->in_w = state->src_w >> 16;
168032a1795fSJyri Sarha 	sp->in_w_uv = sp->in_w;
168132a1795fSJyri Sarha 	sp->in_h = state->src_h >> 16;
168232a1795fSJyri Sarha 	sp->in_h_uv = sp->in_h;
168332a1795fSJyri Sarha 
168432a1795fSJyri Sarha 	sp->scale_x = sp->in_w != state->crtc_w;
168532a1795fSJyri Sarha 	sp->scale_y = sp->in_h != state->crtc_h;
168632a1795fSJyri Sarha 
168732a1795fSJyri Sarha 	if (dispc_fourcc_is_yuv(fourcc)) {
168832a1795fSJyri Sarha 		in_width_max_5tap = f->in_width_max_5tap_yuv;
168932a1795fSJyri Sarha 		in_width_max_3tap = f->in_width_max_3tap_yuv;
169032a1795fSJyri Sarha 
169132a1795fSJyri Sarha 		sp->in_w_uv >>= 1;
169232a1795fSJyri Sarha 		sp->scale_x = true;
169332a1795fSJyri Sarha 
169432a1795fSJyri Sarha 		if (fourcc == DRM_FORMAT_NV12) {
169532a1795fSJyri Sarha 			sp->in_h_uv >>= 1;
169632a1795fSJyri Sarha 			sp->scale_y = true;
169732a1795fSJyri Sarha 		}
169832a1795fSJyri Sarha 	}
169932a1795fSJyri Sarha 
170032a1795fSJyri Sarha 	/* Skip the rest if no scaling is used */
170132a1795fSJyri Sarha 	if ((!sp->scale_x && !sp->scale_y) || lite_plane)
170232a1795fSJyri Sarha 		return 0;
170332a1795fSJyri Sarha 
170432a1795fSJyri Sarha 	if (sp->in_w > in_width_max_5tap) {
170532a1795fSJyri Sarha 		sp->five_taps = false;
170632a1795fSJyri Sarha 		in_width_max = in_width_max_3tap;
170732a1795fSJyri Sarha 		downscale_limit = f->downscale_limit_3tap;
170832a1795fSJyri Sarha 	} else {
170932a1795fSJyri Sarha 		sp->five_taps = true;
171032a1795fSJyri Sarha 		in_width_max = in_width_max_5tap;
171132a1795fSJyri Sarha 		downscale_limit = f->downscale_limit_5tap;
171232a1795fSJyri Sarha 	}
171332a1795fSJyri Sarha 
171432a1795fSJyri Sarha 	if (sp->scale_x) {
171532a1795fSJyri Sarha 		sp->fir_xinc = dispc_calc_fir_inc(sp->in_w, state->crtc_w);
171632a1795fSJyri Sarha 
171732a1795fSJyri Sarha 		if (sp->fir_xinc < dispc_calc_fir_inc(1, f->upscale_limit)) {
171832a1795fSJyri Sarha 			dev_dbg(dispc->dev,
171932a1795fSJyri Sarha 				"%s: X-scaling factor %u/%u > %u\n",
172032a1795fSJyri Sarha 				__func__, state->crtc_w, state->src_w >> 16,
172132a1795fSJyri Sarha 				f->upscale_limit);
172232a1795fSJyri Sarha 			return -EINVAL;
172332a1795fSJyri Sarha 		}
172432a1795fSJyri Sarha 
172532a1795fSJyri Sarha 		if (sp->fir_xinc >= dispc_calc_fir_inc(downscale_limit, 1)) {
172632a1795fSJyri Sarha 			sp->xinc = DIV_ROUND_UP(DIV_ROUND_UP(sp->in_w,
172732a1795fSJyri Sarha 							     state->crtc_w),
172832a1795fSJyri Sarha 						downscale_limit);
172932a1795fSJyri Sarha 
173032a1795fSJyri Sarha 			if (sp->xinc > f->xinc_max) {
173132a1795fSJyri Sarha 				dev_dbg(dispc->dev,
173232a1795fSJyri Sarha 					"%s: X-scaling factor %u/%u < 1/%u\n",
173332a1795fSJyri Sarha 					__func__, state->crtc_w,
173432a1795fSJyri Sarha 					state->src_w >> 16,
173532a1795fSJyri Sarha 					downscale_limit * f->xinc_max);
173632a1795fSJyri Sarha 				return -EINVAL;
173732a1795fSJyri Sarha 			}
173832a1795fSJyri Sarha 
173932a1795fSJyri Sarha 			sp->in_w = (state->src_w >> 16) / sp->xinc;
174032a1795fSJyri Sarha 		}
174132a1795fSJyri Sarha 
174232a1795fSJyri Sarha 		while (sp->in_w > in_width_max) {
174332a1795fSJyri Sarha 			sp->xinc++;
174432a1795fSJyri Sarha 			sp->in_w = (state->src_w >> 16) / sp->xinc;
174532a1795fSJyri Sarha 		}
174632a1795fSJyri Sarha 
174732a1795fSJyri Sarha 		if (sp->xinc > f->xinc_max) {
174832a1795fSJyri Sarha 			dev_dbg(dispc->dev,
1749652f67fdSColin Ian King 				"%s: Too wide input buffer %u > %u\n", __func__,
175032a1795fSJyri Sarha 				state->src_w >> 16, in_width_max * f->xinc_max);
175132a1795fSJyri Sarha 			return -EINVAL;
175232a1795fSJyri Sarha 		}
175332a1795fSJyri Sarha 
175432a1795fSJyri Sarha 		/*
175532a1795fSJyri Sarha 		 * We need even line length for YUV formats. Decimation
175632a1795fSJyri Sarha 		 * can lead to odd length, so we need to make it even
175732a1795fSJyri Sarha 		 * again.
175832a1795fSJyri Sarha 		 */
175932a1795fSJyri Sarha 		if (dispc_fourcc_is_yuv(fourcc))
176032a1795fSJyri Sarha 			sp->in_w &= ~1;
176132a1795fSJyri Sarha 
176232a1795fSJyri Sarha 		sp->fir_xinc = dispc_calc_fir_inc(sp->in_w, state->crtc_w);
176332a1795fSJyri Sarha 	}
176432a1795fSJyri Sarha 
176532a1795fSJyri Sarha 	if (sp->scale_y) {
176632a1795fSJyri Sarha 		sp->fir_yinc = dispc_calc_fir_inc(sp->in_h, state->crtc_h);
176732a1795fSJyri Sarha 
176832a1795fSJyri Sarha 		if (sp->fir_yinc < dispc_calc_fir_inc(1, f->upscale_limit)) {
176932a1795fSJyri Sarha 			dev_dbg(dispc->dev,
177032a1795fSJyri Sarha 				"%s: Y-scaling factor %u/%u > %u\n",
177132a1795fSJyri Sarha 				__func__, state->crtc_h, state->src_h >> 16,
177232a1795fSJyri Sarha 				f->upscale_limit);
177332a1795fSJyri Sarha 			return -EINVAL;
177432a1795fSJyri Sarha 		}
177532a1795fSJyri Sarha 
177632a1795fSJyri Sarha 		if (sp->fir_yinc >= dispc_calc_fir_inc(downscale_limit, 1)) {
177732a1795fSJyri Sarha 			sp->yinc = DIV_ROUND_UP(DIV_ROUND_UP(sp->in_h,
177832a1795fSJyri Sarha 							     state->crtc_h),
177932a1795fSJyri Sarha 						downscale_limit);
178032a1795fSJyri Sarha 
178132a1795fSJyri Sarha 			sp->in_h /= sp->yinc;
178232a1795fSJyri Sarha 			sp->fir_yinc = dispc_calc_fir_inc(sp->in_h,
178332a1795fSJyri Sarha 							  state->crtc_h);
178432a1795fSJyri Sarha 		}
178532a1795fSJyri Sarha 	}
178632a1795fSJyri Sarha 
178732a1795fSJyri Sarha 	dev_dbg(dispc->dev,
178832a1795fSJyri Sarha 		"%s: %ux%u decim %ux%u -> %ux%u firinc %u.%03ux%u.%03u taps %u -> %ux%u\n",
178932a1795fSJyri Sarha 		__func__, state->src_w >> 16, state->src_h >> 16,
179032a1795fSJyri Sarha 		sp->xinc, sp->yinc, sp->in_w, sp->in_h,
179132a1795fSJyri Sarha 		sp->fir_xinc / 0x200000u,
179232a1795fSJyri Sarha 		((sp->fir_xinc & 0x1FFFFFu) * 999u) / 0x1FFFFFu,
179332a1795fSJyri Sarha 		sp->fir_yinc / 0x200000u,
179432a1795fSJyri Sarha 		((sp->fir_yinc & 0x1FFFFFu) * 999u) / 0x1FFFFFu,
179532a1795fSJyri Sarha 		sp->five_taps ? 5 : 3,
179632a1795fSJyri Sarha 		state->crtc_w, state->crtc_h);
179732a1795fSJyri Sarha 
179832a1795fSJyri Sarha 	if (dispc_fourcc_is_yuv(fourcc)) {
179932a1795fSJyri Sarha 		if (sp->scale_x) {
180032a1795fSJyri Sarha 			sp->in_w_uv /= sp->xinc;
180132a1795fSJyri Sarha 			sp->fir_xinc_uv = dispc_calc_fir_inc(sp->in_w_uv,
180232a1795fSJyri Sarha 							     state->crtc_w);
180332a1795fSJyri Sarha 			sp->xcoef_uv = tidss_get_scale_coefs(dispc->dev,
180432a1795fSJyri Sarha 							     sp->fir_xinc_uv,
180532a1795fSJyri Sarha 							     true);
180632a1795fSJyri Sarha 		}
180732a1795fSJyri Sarha 		if (sp->scale_y) {
180832a1795fSJyri Sarha 			sp->in_h_uv /= sp->yinc;
180932a1795fSJyri Sarha 			sp->fir_yinc_uv = dispc_calc_fir_inc(sp->in_h_uv,
181032a1795fSJyri Sarha 							     state->crtc_h);
181132a1795fSJyri Sarha 			sp->ycoef_uv = tidss_get_scale_coefs(dispc->dev,
181232a1795fSJyri Sarha 							     sp->fir_yinc_uv,
181332a1795fSJyri Sarha 							     sp->five_taps);
181432a1795fSJyri Sarha 		}
181532a1795fSJyri Sarha 	}
181632a1795fSJyri Sarha 
181732a1795fSJyri Sarha 	if (sp->scale_x)
181832a1795fSJyri Sarha 		sp->xcoef = tidss_get_scale_coefs(dispc->dev, sp->fir_xinc,
181932a1795fSJyri Sarha 						  true);
182032a1795fSJyri Sarha 
182132a1795fSJyri Sarha 	if (sp->scale_y)
182232a1795fSJyri Sarha 		sp->ycoef = tidss_get_scale_coefs(dispc->dev, sp->fir_yinc,
182332a1795fSJyri Sarha 						  sp->five_taps);
182432a1795fSJyri Sarha 
182532a1795fSJyri Sarha 	return 0;
182632a1795fSJyri Sarha }
182732a1795fSJyri Sarha 
dispc_vid_set_scaling(struct dispc_device * dispc,u32 hw_plane,struct dispc_scaling_params * sp,u32 fourcc)182832a1795fSJyri Sarha static void dispc_vid_set_scaling(struct dispc_device *dispc,
182932a1795fSJyri Sarha 				  u32 hw_plane,
183032a1795fSJyri Sarha 				  struct dispc_scaling_params *sp,
183132a1795fSJyri Sarha 				  u32 fourcc)
183232a1795fSJyri Sarha {
183332a1795fSJyri Sarha 	/* HORIZONTAL RESIZE ENABLE */
183432a1795fSJyri Sarha 	VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES,
183532a1795fSJyri Sarha 			sp->scale_x, 7, 7);
183632a1795fSJyri Sarha 
183732a1795fSJyri Sarha 	/* VERTICAL RESIZE ENABLE */
183832a1795fSJyri Sarha 	VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES,
183932a1795fSJyri Sarha 			sp->scale_y, 8, 8);
184032a1795fSJyri Sarha 
184132a1795fSJyri Sarha 	/* Skip the rest if no scaling is used */
184232a1795fSJyri Sarha 	if (!sp->scale_x && !sp->scale_y)
184332a1795fSJyri Sarha 		return;
184432a1795fSJyri Sarha 
184532a1795fSJyri Sarha 	/* VERTICAL 5-TAPS  */
184632a1795fSJyri Sarha 	VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES,
184732a1795fSJyri Sarha 			sp->five_taps, 21, 21);
184832a1795fSJyri Sarha 
184932a1795fSJyri Sarha 	if (dispc_fourcc_is_yuv(fourcc)) {
185032a1795fSJyri Sarha 		if (sp->scale_x) {
185132a1795fSJyri Sarha 			dispc_vid_write(dispc, hw_plane, DISPC_VID_FIRH2,
185232a1795fSJyri Sarha 					sp->fir_xinc_uv);
185332a1795fSJyri Sarha 			dispc_vid_write_fir_coefs(dispc, hw_plane,
185432a1795fSJyri Sarha 						  DISPC_VID_FIR_COEF_HORIZ_UV,
185532a1795fSJyri Sarha 						  sp->xcoef_uv);
185632a1795fSJyri Sarha 		}
185732a1795fSJyri Sarha 		if (sp->scale_y) {
185832a1795fSJyri Sarha 			dispc_vid_write(dispc, hw_plane, DISPC_VID_FIRV2,
185932a1795fSJyri Sarha 					sp->fir_yinc_uv);
186032a1795fSJyri Sarha 			dispc_vid_write_fir_coefs(dispc, hw_plane,
186132a1795fSJyri Sarha 						  DISPC_VID_FIR_COEF_VERT_UV,
186232a1795fSJyri Sarha 						  sp->ycoef_uv);
186332a1795fSJyri Sarha 		}
186432a1795fSJyri Sarha 	}
186532a1795fSJyri Sarha 
186632a1795fSJyri Sarha 	if (sp->scale_x) {
186732a1795fSJyri Sarha 		dispc_vid_write(dispc, hw_plane, DISPC_VID_FIRH, sp->fir_xinc);
186832a1795fSJyri Sarha 		dispc_vid_write_fir_coefs(dispc, hw_plane,
186932a1795fSJyri Sarha 					  DISPC_VID_FIR_COEF_HORIZ,
187032a1795fSJyri Sarha 					  sp->xcoef);
187132a1795fSJyri Sarha 	}
187232a1795fSJyri Sarha 
187332a1795fSJyri Sarha 	if (sp->scale_y) {
187432a1795fSJyri Sarha 		dispc_vid_write(dispc, hw_plane, DISPC_VID_FIRV, sp->fir_yinc);
187532a1795fSJyri Sarha 		dispc_vid_write_fir_coefs(dispc, hw_plane,
187632a1795fSJyri Sarha 					  DISPC_VID_FIR_COEF_VERT, sp->ycoef);
187732a1795fSJyri Sarha 	}
187832a1795fSJyri Sarha }
187932a1795fSJyri Sarha 
188032a1795fSJyri Sarha /* OTHER */
188132a1795fSJyri Sarha 
188232a1795fSJyri Sarha static const struct {
188332a1795fSJyri Sarha 	u32 fourcc;
188432a1795fSJyri Sarha 	u8 dss_code;
188532a1795fSJyri Sarha } dispc_color_formats[] = {
188632a1795fSJyri Sarha 	{ DRM_FORMAT_ARGB4444, 0x0, },
188732a1795fSJyri Sarha 	{ DRM_FORMAT_ABGR4444, 0x1, },
188832a1795fSJyri Sarha 	{ DRM_FORMAT_RGBA4444, 0x2, },
188932a1795fSJyri Sarha 
189032a1795fSJyri Sarha 	{ DRM_FORMAT_RGB565, 0x3, },
189132a1795fSJyri Sarha 	{ DRM_FORMAT_BGR565, 0x4, },
189232a1795fSJyri Sarha 
189332a1795fSJyri Sarha 	{ DRM_FORMAT_ARGB1555, 0x5, },
189432a1795fSJyri Sarha 	{ DRM_FORMAT_ABGR1555, 0x6, },
189532a1795fSJyri Sarha 
189632a1795fSJyri Sarha 	{ DRM_FORMAT_ARGB8888, 0x7, },
189732a1795fSJyri Sarha 	{ DRM_FORMAT_ABGR8888, 0x8, },
189832a1795fSJyri Sarha 	{ DRM_FORMAT_RGBA8888, 0x9, },
189932a1795fSJyri Sarha 	{ DRM_FORMAT_BGRA8888, 0xa, },
190032a1795fSJyri Sarha 
190132a1795fSJyri Sarha 	{ DRM_FORMAT_RGB888, 0xb, },
190232a1795fSJyri Sarha 	{ DRM_FORMAT_BGR888, 0xc, },
190332a1795fSJyri Sarha 
190432a1795fSJyri Sarha 	{ DRM_FORMAT_ARGB2101010, 0xe, },
190532a1795fSJyri Sarha 	{ DRM_FORMAT_ABGR2101010, 0xf, },
190632a1795fSJyri Sarha 
190732a1795fSJyri Sarha 	{ DRM_FORMAT_XRGB4444, 0x20, },
190832a1795fSJyri Sarha 	{ DRM_FORMAT_XBGR4444, 0x21, },
190932a1795fSJyri Sarha 	{ DRM_FORMAT_RGBX4444, 0x22, },
191032a1795fSJyri Sarha 
19112df0433bSRandolph Sapp 	{ DRM_FORMAT_XRGB1555, 0x25, },
19122df0433bSRandolph Sapp 	{ DRM_FORMAT_XBGR1555, 0x26, },
191332a1795fSJyri Sarha 
191432a1795fSJyri Sarha 	{ DRM_FORMAT_XRGB8888, 0x27, },
191532a1795fSJyri Sarha 	{ DRM_FORMAT_XBGR8888, 0x28, },
191632a1795fSJyri Sarha 	{ DRM_FORMAT_RGBX8888, 0x29, },
191732a1795fSJyri Sarha 	{ DRM_FORMAT_BGRX8888, 0x2a, },
191832a1795fSJyri Sarha 
191932a1795fSJyri Sarha 	{ DRM_FORMAT_XRGB2101010, 0x2e, },
192032a1795fSJyri Sarha 	{ DRM_FORMAT_XBGR2101010, 0x2f, },
192132a1795fSJyri Sarha 
192232a1795fSJyri Sarha 	{ DRM_FORMAT_YUYV, 0x3e, },
192332a1795fSJyri Sarha 	{ DRM_FORMAT_UYVY, 0x3f, },
192432a1795fSJyri Sarha 
192532a1795fSJyri Sarha 	{ DRM_FORMAT_NV12, 0x3d, },
192632a1795fSJyri Sarha };
192732a1795fSJyri Sarha 
dispc_plane_set_pixel_format(struct dispc_device * dispc,u32 hw_plane,u32 fourcc)192832a1795fSJyri Sarha static void dispc_plane_set_pixel_format(struct dispc_device *dispc,
192932a1795fSJyri Sarha 					 u32 hw_plane, u32 fourcc)
193032a1795fSJyri Sarha {
193132a1795fSJyri Sarha 	unsigned int i;
193232a1795fSJyri Sarha 
193332a1795fSJyri Sarha 	for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i) {
193432a1795fSJyri Sarha 		if (dispc_color_formats[i].fourcc == fourcc) {
193532a1795fSJyri Sarha 			VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES,
193632a1795fSJyri Sarha 					dispc_color_formats[i].dss_code,
193732a1795fSJyri Sarha 					6, 1);
193832a1795fSJyri Sarha 			return;
193932a1795fSJyri Sarha 		}
194032a1795fSJyri Sarha 	}
194132a1795fSJyri Sarha 
194232a1795fSJyri Sarha 	WARN_ON(1);
194332a1795fSJyri Sarha }
194432a1795fSJyri Sarha 
dispc_plane_formats(struct dispc_device * dispc,unsigned int * len)194532a1795fSJyri Sarha const u32 *dispc_plane_formats(struct dispc_device *dispc, unsigned int *len)
194632a1795fSJyri Sarha {
194732a1795fSJyri Sarha 	WARN_ON(!dispc->fourccs);
194832a1795fSJyri Sarha 
194932a1795fSJyri Sarha 	*len = dispc->num_fourccs;
195032a1795fSJyri Sarha 
195132a1795fSJyri Sarha 	return dispc->fourccs;
195232a1795fSJyri Sarha }
195332a1795fSJyri Sarha 
pixinc(int pixels,u8 ps)195432a1795fSJyri Sarha static s32 pixinc(int pixels, u8 ps)
195532a1795fSJyri Sarha {
195632a1795fSJyri Sarha 	if (pixels == 1)
195732a1795fSJyri Sarha 		return 1;
195832a1795fSJyri Sarha 	else if (pixels > 1)
195932a1795fSJyri Sarha 		return 1 + (pixels - 1) * ps;
196032a1795fSJyri Sarha 	else if (pixels < 0)
196132a1795fSJyri Sarha 		return 1 - (-pixels + 1) * ps;
196232a1795fSJyri Sarha 
196332a1795fSJyri Sarha 	WARN_ON(1);
196432a1795fSJyri Sarha 	return 0;
196532a1795fSJyri Sarha }
196632a1795fSJyri Sarha 
dispc_plane_check(struct dispc_device * dispc,u32 hw_plane,const struct drm_plane_state * state,u32 hw_videoport)196732a1795fSJyri Sarha int dispc_plane_check(struct dispc_device *dispc, u32 hw_plane,
196832a1795fSJyri Sarha 		      const struct drm_plane_state *state,
196932a1795fSJyri Sarha 		      u32 hw_videoport)
197032a1795fSJyri Sarha {
197132a1795fSJyri Sarha 	bool lite = dispc->feat->vid_lite[hw_plane];
197232a1795fSJyri Sarha 	u32 fourcc = state->fb->format->format;
197332a1795fSJyri Sarha 	bool need_scaling = state->src_w >> 16 != state->crtc_w ||
197432a1795fSJyri Sarha 		state->src_h >> 16 != state->crtc_h;
197532a1795fSJyri Sarha 	struct dispc_scaling_params scaling;
197632a1795fSJyri Sarha 	int ret;
197732a1795fSJyri Sarha 
197832a1795fSJyri Sarha 	if (dispc_fourcc_is_yuv(fourcc)) {
197932a1795fSJyri Sarha 		if (!dispc_find_csc(state->color_encoding,
198032a1795fSJyri Sarha 				    state->color_range)) {
198132a1795fSJyri Sarha 			dev_dbg(dispc->dev,
198232a1795fSJyri Sarha 				"%s: Unsupported CSC (%u,%u) for HW plane %u\n",
198332a1795fSJyri Sarha 				__func__, state->color_encoding,
198432a1795fSJyri Sarha 				state->color_range, hw_plane);
198532a1795fSJyri Sarha 			return -EINVAL;
198632a1795fSJyri Sarha 		}
198732a1795fSJyri Sarha 	}
198832a1795fSJyri Sarha 
198932a1795fSJyri Sarha 	if (need_scaling) {
199032a1795fSJyri Sarha 		if (lite) {
199132a1795fSJyri Sarha 			dev_dbg(dispc->dev,
199232a1795fSJyri Sarha 				"%s: Lite plane %u can't scale %ux%u!=%ux%u\n",
199332a1795fSJyri Sarha 				__func__, hw_plane,
199432a1795fSJyri Sarha 				state->src_w >> 16, state->src_h >> 16,
199532a1795fSJyri Sarha 				state->crtc_w, state->crtc_h);
199632a1795fSJyri Sarha 			return -EINVAL;
199732a1795fSJyri Sarha 		}
199832a1795fSJyri Sarha 		ret = dispc_vid_calc_scaling(dispc, state, &scaling, false);
199932a1795fSJyri Sarha 		if (ret)
200032a1795fSJyri Sarha 			return ret;
200132a1795fSJyri Sarha 	}
200232a1795fSJyri Sarha 
200332a1795fSJyri Sarha 	return 0;
200432a1795fSJyri Sarha }
200532a1795fSJyri Sarha 
200632a1795fSJyri Sarha static
dispc_plane_state_dma_addr(const struct drm_plane_state * state)20078c30eeccSDanilo Krummrich dma_addr_t dispc_plane_state_dma_addr(const struct drm_plane_state *state)
200832a1795fSJyri Sarha {
200932a1795fSJyri Sarha 	struct drm_framebuffer *fb = state->fb;
20104a83c26aSDanilo Krummrich 	struct drm_gem_dma_object *gem;
201132a1795fSJyri Sarha 	u32 x = state->src_x >> 16;
201232a1795fSJyri Sarha 	u32 y = state->src_y >> 16;
201332a1795fSJyri Sarha 
20146bcfe8eaSDanilo Krummrich 	gem = drm_fb_dma_get_gem_obj(state->fb, 0);
201532a1795fSJyri Sarha 
20168c30eeccSDanilo Krummrich 	return gem->dma_addr + fb->offsets[0] + x * fb->format->cpp[0] +
201732a1795fSJyri Sarha 		y * fb->pitches[0];
201832a1795fSJyri Sarha }
201932a1795fSJyri Sarha 
202032a1795fSJyri Sarha static
dispc_plane_state_p_uv_addr(const struct drm_plane_state * state)202132a1795fSJyri Sarha dma_addr_t dispc_plane_state_p_uv_addr(const struct drm_plane_state *state)
202232a1795fSJyri Sarha {
202332a1795fSJyri Sarha 	struct drm_framebuffer *fb = state->fb;
20244a83c26aSDanilo Krummrich 	struct drm_gem_dma_object *gem;
202532a1795fSJyri Sarha 	u32 x = state->src_x >> 16;
202632a1795fSJyri Sarha 	u32 y = state->src_y >> 16;
202732a1795fSJyri Sarha 
202832a1795fSJyri Sarha 	if (WARN_ON(state->fb->format->num_planes != 2))
202932a1795fSJyri Sarha 		return 0;
203032a1795fSJyri Sarha 
20316bcfe8eaSDanilo Krummrich 	gem = drm_fb_dma_get_gem_obj(fb, 1);
203232a1795fSJyri Sarha 
20338c30eeccSDanilo Krummrich 	return gem->dma_addr + fb->offsets[1] +
203432a1795fSJyri Sarha 		(x * fb->format->cpp[1] / fb->format->hsub) +
203532a1795fSJyri Sarha 		(y * fb->pitches[1] / fb->format->vsub);
203632a1795fSJyri Sarha }
203732a1795fSJyri Sarha 
dispc_plane_setup(struct dispc_device * dispc,u32 hw_plane,const struct drm_plane_state * state,u32 hw_videoport)2038e1174133SThomas Zimmermann void dispc_plane_setup(struct dispc_device *dispc, u32 hw_plane,
203932a1795fSJyri Sarha 		       const struct drm_plane_state *state,
204032a1795fSJyri Sarha 		       u32 hw_videoport)
204132a1795fSJyri Sarha {
204232a1795fSJyri Sarha 	bool lite = dispc->feat->vid_lite[hw_plane];
204332a1795fSJyri Sarha 	u32 fourcc = state->fb->format->format;
204432a1795fSJyri Sarha 	u16 cpp = state->fb->format->cpp[0];
204532a1795fSJyri Sarha 	u32 fb_width = state->fb->pitches[0] / cpp;
20468c30eeccSDanilo Krummrich 	dma_addr_t dma_addr = dispc_plane_state_dma_addr(state);
204732a1795fSJyri Sarha 	struct dispc_scaling_params scale;
204832a1795fSJyri Sarha 
204932a1795fSJyri Sarha 	dispc_vid_calc_scaling(dispc, state, &scale, lite);
205032a1795fSJyri Sarha 
205132a1795fSJyri Sarha 	dispc_plane_set_pixel_format(dispc, hw_plane, fourcc);
205232a1795fSJyri Sarha 
20538c30eeccSDanilo Krummrich 	dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_0, dma_addr & 0xffffffff);
20548c30eeccSDanilo Krummrich 	dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_EXT_0, (u64)dma_addr >> 32);
20558c30eeccSDanilo Krummrich 	dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_1, dma_addr & 0xffffffff);
20568c30eeccSDanilo Krummrich 	dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_EXT_1, (u64)dma_addr >> 32);
205732a1795fSJyri Sarha 
205832a1795fSJyri Sarha 	dispc_vid_write(dispc, hw_plane, DISPC_VID_PICTURE_SIZE,
205932a1795fSJyri Sarha 			(scale.in_w - 1) | ((scale.in_h - 1) << 16));
206032a1795fSJyri Sarha 
206132a1795fSJyri Sarha 	/* For YUV422 format we use the macropixel size for pixel inc */
206232a1795fSJyri Sarha 	if (fourcc == DRM_FORMAT_YUYV || fourcc == DRM_FORMAT_UYVY)
206332a1795fSJyri Sarha 		dispc_vid_write(dispc, hw_plane, DISPC_VID_PIXEL_INC,
206432a1795fSJyri Sarha 				pixinc(scale.xinc, cpp * 2));
206532a1795fSJyri Sarha 	else
206632a1795fSJyri Sarha 		dispc_vid_write(dispc, hw_plane, DISPC_VID_PIXEL_INC,
206732a1795fSJyri Sarha 				pixinc(scale.xinc, cpp));
206832a1795fSJyri Sarha 
206932a1795fSJyri Sarha 	dispc_vid_write(dispc, hw_plane, DISPC_VID_ROW_INC,
207032a1795fSJyri Sarha 			pixinc(1 + (scale.yinc * fb_width -
207132a1795fSJyri Sarha 				    scale.xinc * scale.in_w),
207232a1795fSJyri Sarha 			       cpp));
207332a1795fSJyri Sarha 
207432a1795fSJyri Sarha 	if (state->fb->format->num_planes == 2) {
207532a1795fSJyri Sarha 		u16 cpp_uv = state->fb->format->cpp[1];
207632a1795fSJyri Sarha 		u32 fb_width_uv = state->fb->pitches[1] / cpp_uv;
207732a1795fSJyri Sarha 		dma_addr_t p_uv_addr = dispc_plane_state_p_uv_addr(state);
207832a1795fSJyri Sarha 
207932a1795fSJyri Sarha 		dispc_vid_write(dispc, hw_plane,
208032a1795fSJyri Sarha 				DISPC_VID_BA_UV_0, p_uv_addr & 0xffffffff);
208132a1795fSJyri Sarha 		dispc_vid_write(dispc, hw_plane,
208232a1795fSJyri Sarha 				DISPC_VID_BA_UV_EXT_0, (u64)p_uv_addr >> 32);
208332a1795fSJyri Sarha 		dispc_vid_write(dispc, hw_plane,
208432a1795fSJyri Sarha 				DISPC_VID_BA_UV_1, p_uv_addr & 0xffffffff);
208532a1795fSJyri Sarha 		dispc_vid_write(dispc, hw_plane,
208632a1795fSJyri Sarha 				DISPC_VID_BA_UV_EXT_1, (u64)p_uv_addr >> 32);
208732a1795fSJyri Sarha 
208832a1795fSJyri Sarha 		dispc_vid_write(dispc, hw_plane, DISPC_VID_ROW_INC_UV,
208932a1795fSJyri Sarha 				pixinc(1 + (scale.yinc * fb_width_uv -
209032a1795fSJyri Sarha 					    scale.xinc * scale.in_w_uv),
209132a1795fSJyri Sarha 				       cpp_uv));
209232a1795fSJyri Sarha 	}
209332a1795fSJyri Sarha 
209432a1795fSJyri Sarha 	if (!lite) {
209532a1795fSJyri Sarha 		dispc_vid_write(dispc, hw_plane, DISPC_VID_SIZE,
209632a1795fSJyri Sarha 				(state->crtc_w - 1) |
209732a1795fSJyri Sarha 				((state->crtc_h - 1) << 16));
209832a1795fSJyri Sarha 
209932a1795fSJyri Sarha 		dispc_vid_set_scaling(dispc, hw_plane, &scale, fourcc);
210032a1795fSJyri Sarha 	}
210132a1795fSJyri Sarha 
210232a1795fSJyri Sarha 	/* enable YUV->RGB color conversion */
210332a1795fSJyri Sarha 	if (dispc_fourcc_is_yuv(fourcc)) {
210432a1795fSJyri Sarha 		dispc_vid_csc_setup(dispc, hw_plane, state);
210532a1795fSJyri Sarha 		dispc_vid_csc_enable(dispc, hw_plane, true);
210632a1795fSJyri Sarha 	} else {
210732a1795fSJyri Sarha 		dispc_vid_csc_enable(dispc, hw_plane, false);
210832a1795fSJyri Sarha 	}
210932a1795fSJyri Sarha 
211032a1795fSJyri Sarha 	dispc_vid_write(dispc, hw_plane, DISPC_VID_GLOBAL_ALPHA,
211132a1795fSJyri Sarha 			0xFF & (state->alpha >> 8));
211232a1795fSJyri Sarha 
211332a1795fSJyri Sarha 	if (state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI)
211432a1795fSJyri Sarha 		VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 1,
211532a1795fSJyri Sarha 				28, 28);
211632a1795fSJyri Sarha 	else
211732a1795fSJyri Sarha 		VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 0,
211832a1795fSJyri Sarha 				28, 28);
211932a1795fSJyri Sarha }
212032a1795fSJyri Sarha 
dispc_plane_enable(struct dispc_device * dispc,u32 hw_plane,bool enable)2121e1174133SThomas Zimmermann void dispc_plane_enable(struct dispc_device *dispc, u32 hw_plane, bool enable)
212232a1795fSJyri Sarha {
212332a1795fSJyri Sarha 	VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, !!enable, 0, 0);
212432a1795fSJyri Sarha }
212532a1795fSJyri Sarha 
dispc_vid_get_fifo_size(struct dispc_device * dispc,u32 hw_plane)212632a1795fSJyri Sarha static u32 dispc_vid_get_fifo_size(struct dispc_device *dispc, u32 hw_plane)
212732a1795fSJyri Sarha {
212832a1795fSJyri Sarha 	return VID_REG_GET(dispc, hw_plane, DISPC_VID_BUF_SIZE_STATUS, 15, 0);
212932a1795fSJyri Sarha }
213032a1795fSJyri Sarha 
dispc_vid_set_mflag_threshold(struct dispc_device * dispc,u32 hw_plane,u32 low,u32 high)213132a1795fSJyri Sarha static void dispc_vid_set_mflag_threshold(struct dispc_device *dispc,
213232a1795fSJyri Sarha 					  u32 hw_plane, u32 low, u32 high)
213332a1795fSJyri Sarha {
213432a1795fSJyri Sarha 	dispc_vid_write(dispc, hw_plane, DISPC_VID_MFLAG_THRESHOLD,
213532a1795fSJyri Sarha 			FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0));
213632a1795fSJyri Sarha }
213732a1795fSJyri Sarha 
dispc_vid_set_buf_threshold(struct dispc_device * dispc,u32 hw_plane,u32 low,u32 high)213832a1795fSJyri Sarha static void dispc_vid_set_buf_threshold(struct dispc_device *dispc,
213932a1795fSJyri Sarha 					u32 hw_plane, u32 low, u32 high)
214032a1795fSJyri Sarha {
214132a1795fSJyri Sarha 	dispc_vid_write(dispc, hw_plane, DISPC_VID_BUF_THRESHOLD,
214232a1795fSJyri Sarha 			FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0));
214332a1795fSJyri Sarha }
214432a1795fSJyri Sarha 
dispc_k2g_plane_init(struct dispc_device * dispc)214532a1795fSJyri Sarha static void dispc_k2g_plane_init(struct dispc_device *dispc)
214632a1795fSJyri Sarha {
214732a1795fSJyri Sarha 	unsigned int hw_plane;
214832a1795fSJyri Sarha 
214932a1795fSJyri Sarha 	dev_dbg(dispc->dev, "%s()\n", __func__);
215032a1795fSJyri Sarha 
215132a1795fSJyri Sarha 	/* MFLAG_CTRL = ENABLED */
215232a1795fSJyri Sarha 	REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 2, 1, 0);
215332a1795fSJyri Sarha 	/* MFLAG_START = MFLAGNORMALSTARTMODE */
215432a1795fSJyri Sarha 	REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 0, 6, 6);
215532a1795fSJyri Sarha 
215632a1795fSJyri Sarha 	for (hw_plane = 0; hw_plane < dispc->feat->num_planes; hw_plane++) {
215732a1795fSJyri Sarha 		u32 size = dispc_vid_get_fifo_size(dispc, hw_plane);
215832a1795fSJyri Sarha 		u32 thr_low, thr_high;
215932a1795fSJyri Sarha 		u32 mflag_low, mflag_high;
216032a1795fSJyri Sarha 		u32 preload;
216132a1795fSJyri Sarha 
216232a1795fSJyri Sarha 		thr_high = size - 1;
216332a1795fSJyri Sarha 		thr_low = size / 2;
216432a1795fSJyri Sarha 
216532a1795fSJyri Sarha 		mflag_high = size * 2 / 3;
216632a1795fSJyri Sarha 		mflag_low = size / 3;
216732a1795fSJyri Sarha 
216832a1795fSJyri Sarha 		preload = thr_low;
216932a1795fSJyri Sarha 
217032a1795fSJyri Sarha 		dev_dbg(dispc->dev,
217132a1795fSJyri Sarha 			"%s: bufsize %u, buf_threshold %u/%u, mflag threshold %u/%u preload %u\n",
217232a1795fSJyri Sarha 			dispc->feat->vid_name[hw_plane],
217332a1795fSJyri Sarha 			size,
217432a1795fSJyri Sarha 			thr_high, thr_low,
217532a1795fSJyri Sarha 			mflag_high, mflag_low,
217632a1795fSJyri Sarha 			preload);
217732a1795fSJyri Sarha 
217832a1795fSJyri Sarha 		dispc_vid_set_buf_threshold(dispc, hw_plane,
217932a1795fSJyri Sarha 					    thr_low, thr_high);
218032a1795fSJyri Sarha 		dispc_vid_set_mflag_threshold(dispc, hw_plane,
218132a1795fSJyri Sarha 					      mflag_low, mflag_high);
218232a1795fSJyri Sarha 
218332a1795fSJyri Sarha 		dispc_vid_write(dispc, hw_plane, DISPC_VID_PRELOAD, preload);
218432a1795fSJyri Sarha 
218532a1795fSJyri Sarha 		/*
218632a1795fSJyri Sarha 		 * Prefetch up to fifo high-threshold value to minimize the
218732a1795fSJyri Sarha 		 * possibility of underflows. Note that this means the PRELOAD
218832a1795fSJyri Sarha 		 * register is ignored.
218932a1795fSJyri Sarha 		 */
219032a1795fSJyri Sarha 		VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 1,
219132a1795fSJyri Sarha 				19, 19);
219232a1795fSJyri Sarha 	}
219332a1795fSJyri Sarha }
219432a1795fSJyri Sarha 
dispc_k3_plane_init(struct dispc_device * dispc)219532a1795fSJyri Sarha static void dispc_k3_plane_init(struct dispc_device *dispc)
219632a1795fSJyri Sarha {
219732a1795fSJyri Sarha 	unsigned int hw_plane;
219832a1795fSJyri Sarha 	u32 cba_lo_pri = 1;
219932a1795fSJyri Sarha 	u32 cba_hi_pri = 0;
220032a1795fSJyri Sarha 
220132a1795fSJyri Sarha 	dev_dbg(dispc->dev, "%s()\n", __func__);
220232a1795fSJyri Sarha 
220332a1795fSJyri Sarha 	REG_FLD_MOD(dispc, DSS_CBA_CFG, cba_lo_pri, 2, 0);
220432a1795fSJyri Sarha 	REG_FLD_MOD(dispc, DSS_CBA_CFG, cba_hi_pri, 5, 3);
220532a1795fSJyri Sarha 
220632a1795fSJyri Sarha 	/* MFLAG_CTRL = ENABLED */
220732a1795fSJyri Sarha 	REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 2, 1, 0);
220832a1795fSJyri Sarha 	/* MFLAG_START = MFLAGNORMALSTARTMODE */
220932a1795fSJyri Sarha 	REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 0, 6, 6);
221032a1795fSJyri Sarha 
221132a1795fSJyri Sarha 	for (hw_plane = 0; hw_plane < dispc->feat->num_planes; hw_plane++) {
221232a1795fSJyri Sarha 		u32 size = dispc_vid_get_fifo_size(dispc, hw_plane);
221332a1795fSJyri Sarha 		u32 thr_low, thr_high;
221432a1795fSJyri Sarha 		u32 mflag_low, mflag_high;
221532a1795fSJyri Sarha 		u32 preload;
221632a1795fSJyri Sarha 
221732a1795fSJyri Sarha 		thr_high = size - 1;
221832a1795fSJyri Sarha 		thr_low = size / 2;
221932a1795fSJyri Sarha 
222032a1795fSJyri Sarha 		mflag_high = size * 2 / 3;
222132a1795fSJyri Sarha 		mflag_low = size / 3;
222232a1795fSJyri Sarha 
222332a1795fSJyri Sarha 		preload = thr_low;
222432a1795fSJyri Sarha 
222532a1795fSJyri Sarha 		dev_dbg(dispc->dev,
222632a1795fSJyri Sarha 			"%s: bufsize %u, buf_threshold %u/%u, mflag threshold %u/%u preload %u\n",
222732a1795fSJyri Sarha 			dispc->feat->vid_name[hw_plane],
222832a1795fSJyri Sarha 			size,
222932a1795fSJyri Sarha 			thr_high, thr_low,
223032a1795fSJyri Sarha 			mflag_high, mflag_low,
223132a1795fSJyri Sarha 			preload);
223232a1795fSJyri Sarha 
223332a1795fSJyri Sarha 		dispc_vid_set_buf_threshold(dispc, hw_plane,
223432a1795fSJyri Sarha 					    thr_low, thr_high);
223532a1795fSJyri Sarha 		dispc_vid_set_mflag_threshold(dispc, hw_plane,
223632a1795fSJyri Sarha 					      mflag_low, mflag_high);
223732a1795fSJyri Sarha 
223832a1795fSJyri Sarha 		dispc_vid_write(dispc, hw_plane, DISPC_VID_PRELOAD, preload);
223932a1795fSJyri Sarha 
224032a1795fSJyri Sarha 		/* Prefech up to PRELOAD value */
224132a1795fSJyri Sarha 		VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 0,
224232a1795fSJyri Sarha 				19, 19);
224332a1795fSJyri Sarha 	}
224432a1795fSJyri Sarha }
224532a1795fSJyri Sarha 
dispc_plane_init(struct dispc_device * dispc)224632a1795fSJyri Sarha static void dispc_plane_init(struct dispc_device *dispc)
224732a1795fSJyri Sarha {
224832a1795fSJyri Sarha 	switch (dispc->feat->subrev) {
224932a1795fSJyri Sarha 	case DISPC_K2G:
225032a1795fSJyri Sarha 		dispc_k2g_plane_init(dispc);
225132a1795fSJyri Sarha 		break;
2252ad2ac9dcSAradhya Bhatia 	case DISPC_AM625:
225332a1795fSJyri Sarha 	case DISPC_AM65X:
225432a1795fSJyri Sarha 	case DISPC_J721E:
225532a1795fSJyri Sarha 		dispc_k3_plane_init(dispc);
225632a1795fSJyri Sarha 		break;
225732a1795fSJyri Sarha 	default:
225832a1795fSJyri Sarha 		WARN_ON(1);
225932a1795fSJyri Sarha 	}
226032a1795fSJyri Sarha }
226132a1795fSJyri Sarha 
dispc_vp_init(struct dispc_device * dispc)226232a1795fSJyri Sarha static void dispc_vp_init(struct dispc_device *dispc)
226332a1795fSJyri Sarha {
226432a1795fSJyri Sarha 	unsigned int i;
226532a1795fSJyri Sarha 
226632a1795fSJyri Sarha 	dev_dbg(dispc->dev, "%s()\n", __func__);
226732a1795fSJyri Sarha 
226832a1795fSJyri Sarha 	/* Enable the gamma Shadow bit-field for all VPs*/
226932a1795fSJyri Sarha 	for (i = 0; i < dispc->feat->num_vps; i++)
227032a1795fSJyri Sarha 		VP_REG_FLD_MOD(dispc, i, DISPC_VP_CONFIG, 1, 2, 2);
227132a1795fSJyri Sarha }
227232a1795fSJyri Sarha 
dispc_initial_config(struct dispc_device * dispc)227332a1795fSJyri Sarha static void dispc_initial_config(struct dispc_device *dispc)
227432a1795fSJyri Sarha {
227532a1795fSJyri Sarha 	dispc_plane_init(dispc);
227632a1795fSJyri Sarha 	dispc_vp_init(dispc);
227732a1795fSJyri Sarha 
227832a1795fSJyri Sarha 	/* Note: Hardcoded DPI routing on J721E for now */
227932a1795fSJyri Sarha 	if (dispc->feat->subrev == DISPC_J721E) {
228032a1795fSJyri Sarha 		dispc_write(dispc, DISPC_CONNECTIONS,
228132a1795fSJyri Sarha 			    FLD_VAL(2, 3, 0) |		/* VP1 to DPI0 */
228232a1795fSJyri Sarha 			    FLD_VAL(8, 7, 4)		/* VP3 to DPI1 */
228332a1795fSJyri Sarha 			);
228432a1795fSJyri Sarha 	}
228532a1795fSJyri Sarha }
228632a1795fSJyri Sarha 
dispc_k2g_vp_write_gamma_table(struct dispc_device * dispc,u32 hw_videoport)228732a1795fSJyri Sarha static void dispc_k2g_vp_write_gamma_table(struct dispc_device *dispc,
228832a1795fSJyri Sarha 					   u32 hw_videoport)
228932a1795fSJyri Sarha {
229032a1795fSJyri Sarha 	u32 *table = dispc->vp_data[hw_videoport].gamma_table;
229132a1795fSJyri Sarha 	u32 hwlen = dispc->feat->vp_feat.color.gamma_size;
229232a1795fSJyri Sarha 	unsigned int i;
229332a1795fSJyri Sarha 
229432a1795fSJyri Sarha 	dev_dbg(dispc->dev, "%s: hw_videoport %d\n", __func__, hw_videoport);
229532a1795fSJyri Sarha 
229632a1795fSJyri Sarha 	if (WARN_ON(dispc->feat->vp_feat.color.gamma_type != TIDSS_GAMMA_8BIT))
229732a1795fSJyri Sarha 		return;
229832a1795fSJyri Sarha 
229932a1795fSJyri Sarha 	for (i = 0; i < hwlen; ++i) {
230032a1795fSJyri Sarha 		u32 v = table[i];
230132a1795fSJyri Sarha 
230232a1795fSJyri Sarha 		v |= i << 24;
230332a1795fSJyri Sarha 
230432a1795fSJyri Sarha 		dispc_vp_write(dispc, hw_videoport, DISPC_VP_K2G_GAMMA_TABLE,
230532a1795fSJyri Sarha 			       v);
230632a1795fSJyri Sarha 	}
230732a1795fSJyri Sarha }
230832a1795fSJyri Sarha 
dispc_am65x_vp_write_gamma_table(struct dispc_device * dispc,u32 hw_videoport)230932a1795fSJyri Sarha static void dispc_am65x_vp_write_gamma_table(struct dispc_device *dispc,
231032a1795fSJyri Sarha 					     u32 hw_videoport)
231132a1795fSJyri Sarha {
231232a1795fSJyri Sarha 	u32 *table = dispc->vp_data[hw_videoport].gamma_table;
231332a1795fSJyri Sarha 	u32 hwlen = dispc->feat->vp_feat.color.gamma_size;
231432a1795fSJyri Sarha 	unsigned int i;
231532a1795fSJyri Sarha 
231632a1795fSJyri Sarha 	dev_dbg(dispc->dev, "%s: hw_videoport %d\n", __func__, hw_videoport);
231732a1795fSJyri Sarha 
231832a1795fSJyri Sarha 	if (WARN_ON(dispc->feat->vp_feat.color.gamma_type != TIDSS_GAMMA_8BIT))
231932a1795fSJyri Sarha 		return;
232032a1795fSJyri Sarha 
232132a1795fSJyri Sarha 	for (i = 0; i < hwlen; ++i) {
232232a1795fSJyri Sarha 		u32 v = table[i];
232332a1795fSJyri Sarha 
232432a1795fSJyri Sarha 		v |= i << 24;
232532a1795fSJyri Sarha 
232632a1795fSJyri Sarha 		dispc_vp_write(dispc, hw_videoport, DISPC_VP_GAMMA_TABLE, v);
232732a1795fSJyri Sarha 	}
232832a1795fSJyri Sarha }
232932a1795fSJyri Sarha 
dispc_j721e_vp_write_gamma_table(struct dispc_device * dispc,u32 hw_videoport)233032a1795fSJyri Sarha static void dispc_j721e_vp_write_gamma_table(struct dispc_device *dispc,
233132a1795fSJyri Sarha 					     u32 hw_videoport)
233232a1795fSJyri Sarha {
233332a1795fSJyri Sarha 	u32 *table = dispc->vp_data[hw_videoport].gamma_table;
233432a1795fSJyri Sarha 	u32 hwlen = dispc->feat->vp_feat.color.gamma_size;
233532a1795fSJyri Sarha 	unsigned int i;
233632a1795fSJyri Sarha 
233732a1795fSJyri Sarha 	dev_dbg(dispc->dev, "%s: hw_videoport %d\n", __func__, hw_videoport);
233832a1795fSJyri Sarha 
233932a1795fSJyri Sarha 	if (WARN_ON(dispc->feat->vp_feat.color.gamma_type != TIDSS_GAMMA_10BIT))
234032a1795fSJyri Sarha 		return;
234132a1795fSJyri Sarha 
234232a1795fSJyri Sarha 	for (i = 0; i < hwlen; ++i) {
234332a1795fSJyri Sarha 		u32 v = table[i];
234432a1795fSJyri Sarha 
234532a1795fSJyri Sarha 		if (i == 0)
234632a1795fSJyri Sarha 			v |= 1 << 31;
234732a1795fSJyri Sarha 
234832a1795fSJyri Sarha 		dispc_vp_write(dispc, hw_videoport, DISPC_VP_GAMMA_TABLE, v);
234932a1795fSJyri Sarha 	}
235032a1795fSJyri Sarha }
235132a1795fSJyri Sarha 
dispc_vp_write_gamma_table(struct dispc_device * dispc,u32 hw_videoport)235232a1795fSJyri Sarha static void dispc_vp_write_gamma_table(struct dispc_device *dispc,
235332a1795fSJyri Sarha 				       u32 hw_videoport)
235432a1795fSJyri Sarha {
235532a1795fSJyri Sarha 	switch (dispc->feat->subrev) {
235632a1795fSJyri Sarha 	case DISPC_K2G:
235732a1795fSJyri Sarha 		dispc_k2g_vp_write_gamma_table(dispc, hw_videoport);
235832a1795fSJyri Sarha 		break;
2359ad2ac9dcSAradhya Bhatia 	case DISPC_AM625:
236032a1795fSJyri Sarha 	case DISPC_AM65X:
236132a1795fSJyri Sarha 		dispc_am65x_vp_write_gamma_table(dispc, hw_videoport);
236232a1795fSJyri Sarha 		break;
236332a1795fSJyri Sarha 	case DISPC_J721E:
236432a1795fSJyri Sarha 		dispc_j721e_vp_write_gamma_table(dispc, hw_videoport);
236532a1795fSJyri Sarha 		break;
236632a1795fSJyri Sarha 	default:
236732a1795fSJyri Sarha 		WARN_ON(1);
236832a1795fSJyri Sarha 		break;
236932a1795fSJyri Sarha 	}
237032a1795fSJyri Sarha }
237132a1795fSJyri Sarha 
237232a1795fSJyri Sarha static const struct drm_color_lut dispc_vp_gamma_default_lut[] = {
237332a1795fSJyri Sarha 	{ .red = 0, .green = 0, .blue = 0, },
237432a1795fSJyri Sarha 	{ .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, },
237532a1795fSJyri Sarha };
237632a1795fSJyri Sarha 
dispc_vp_set_gamma(struct dispc_device * dispc,u32 hw_videoport,const struct drm_color_lut * lut,unsigned int length)237732a1795fSJyri Sarha static void dispc_vp_set_gamma(struct dispc_device *dispc,
237832a1795fSJyri Sarha 			       u32 hw_videoport,
237932a1795fSJyri Sarha 			       const struct drm_color_lut *lut,
238032a1795fSJyri Sarha 			       unsigned int length)
238132a1795fSJyri Sarha {
238232a1795fSJyri Sarha 	u32 *table = dispc->vp_data[hw_videoport].gamma_table;
238332a1795fSJyri Sarha 	u32 hwlen = dispc->feat->vp_feat.color.gamma_size;
238432a1795fSJyri Sarha 	u32 hwbits;
238532a1795fSJyri Sarha 	unsigned int i;
238632a1795fSJyri Sarha 
238732a1795fSJyri Sarha 	dev_dbg(dispc->dev, "%s: hw_videoport %d, lut len %u, hw len %u\n",
238832a1795fSJyri Sarha 		__func__, hw_videoport, length, hwlen);
238932a1795fSJyri Sarha 
239032a1795fSJyri Sarha 	if (dispc->feat->vp_feat.color.gamma_type == TIDSS_GAMMA_10BIT)
239132a1795fSJyri Sarha 		hwbits = 10;
239232a1795fSJyri Sarha 	else
239332a1795fSJyri Sarha 		hwbits = 8;
239432a1795fSJyri Sarha 
239532a1795fSJyri Sarha 	if (!lut || length < 2) {
239632a1795fSJyri Sarha 		lut = dispc_vp_gamma_default_lut;
239732a1795fSJyri Sarha 		length = ARRAY_SIZE(dispc_vp_gamma_default_lut);
239832a1795fSJyri Sarha 	}
239932a1795fSJyri Sarha 
240032a1795fSJyri Sarha 	for (i = 0; i < length - 1; ++i) {
240132a1795fSJyri Sarha 		unsigned int first = i * (hwlen - 1) / (length - 1);
240232a1795fSJyri Sarha 		unsigned int last = (i + 1) * (hwlen - 1) / (length - 1);
240332a1795fSJyri Sarha 		unsigned int w = last - first;
240432a1795fSJyri Sarha 		u16 r, g, b;
240532a1795fSJyri Sarha 		unsigned int j;
240632a1795fSJyri Sarha 
240732a1795fSJyri Sarha 		if (w == 0)
240832a1795fSJyri Sarha 			continue;
240932a1795fSJyri Sarha 
241032a1795fSJyri Sarha 		for (j = 0; j <= w; j++) {
241132a1795fSJyri Sarha 			r = (lut[i].red * (w - j) + lut[i + 1].red * j) / w;
241232a1795fSJyri Sarha 			g = (lut[i].green * (w - j) + lut[i + 1].green * j) / w;
241332a1795fSJyri Sarha 			b = (lut[i].blue * (w - j) + lut[i + 1].blue * j) / w;
241432a1795fSJyri Sarha 
241532a1795fSJyri Sarha 			r >>= 16 - hwbits;
241632a1795fSJyri Sarha 			g >>= 16 - hwbits;
241732a1795fSJyri Sarha 			b >>= 16 - hwbits;
241832a1795fSJyri Sarha 
241932a1795fSJyri Sarha 			table[first + j] = (r << (hwbits * 2)) |
242032a1795fSJyri Sarha 				(g << hwbits) | b;
242132a1795fSJyri Sarha 		}
242232a1795fSJyri Sarha 	}
242332a1795fSJyri Sarha 
242432a1795fSJyri Sarha 	dispc_vp_write_gamma_table(dispc, hw_videoport);
242532a1795fSJyri Sarha }
242632a1795fSJyri Sarha 
dispc_S31_32_to_s2_8(s64 coef)242732a1795fSJyri Sarha static s16 dispc_S31_32_to_s2_8(s64 coef)
242832a1795fSJyri Sarha {
242932a1795fSJyri Sarha 	u64 sign_bit = 1ULL << 63;
243032a1795fSJyri Sarha 	u64 cbits = (u64)coef;
243132a1795fSJyri Sarha 	s16 ret;
243232a1795fSJyri Sarha 
243332a1795fSJyri Sarha 	if (cbits & sign_bit)
243432a1795fSJyri Sarha 		ret = -clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x200);
243532a1795fSJyri Sarha 	else
243632a1795fSJyri Sarha 		ret = clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x1FF);
243732a1795fSJyri Sarha 
243832a1795fSJyri Sarha 	return ret;
243932a1795fSJyri Sarha }
244032a1795fSJyri Sarha 
dispc_k2g_cpr_from_ctm(const struct drm_color_ctm * ctm,struct dispc_csc_coef * cpr)244132a1795fSJyri Sarha static void dispc_k2g_cpr_from_ctm(const struct drm_color_ctm *ctm,
244232a1795fSJyri Sarha 				   struct dispc_csc_coef *cpr)
244332a1795fSJyri Sarha {
244432a1795fSJyri Sarha 	memset(cpr, 0, sizeof(*cpr));
244532a1795fSJyri Sarha 
244632a1795fSJyri Sarha 	cpr->to_regval = dispc_csc_cpr_regval;
244732a1795fSJyri Sarha 	cpr->m[CSC_RR] = dispc_S31_32_to_s2_8(ctm->matrix[0]);
244832a1795fSJyri Sarha 	cpr->m[CSC_RG] = dispc_S31_32_to_s2_8(ctm->matrix[1]);
244932a1795fSJyri Sarha 	cpr->m[CSC_RB] = dispc_S31_32_to_s2_8(ctm->matrix[2]);
245032a1795fSJyri Sarha 	cpr->m[CSC_GR] = dispc_S31_32_to_s2_8(ctm->matrix[3]);
245132a1795fSJyri Sarha 	cpr->m[CSC_GG] = dispc_S31_32_to_s2_8(ctm->matrix[4]);
245232a1795fSJyri Sarha 	cpr->m[CSC_GB] = dispc_S31_32_to_s2_8(ctm->matrix[5]);
245332a1795fSJyri Sarha 	cpr->m[CSC_BR] = dispc_S31_32_to_s2_8(ctm->matrix[6]);
245432a1795fSJyri Sarha 	cpr->m[CSC_BG] = dispc_S31_32_to_s2_8(ctm->matrix[7]);
245532a1795fSJyri Sarha 	cpr->m[CSC_BB] = dispc_S31_32_to_s2_8(ctm->matrix[8]);
245632a1795fSJyri Sarha }
245732a1795fSJyri Sarha 
245832a1795fSJyri Sarha #define CVAL(xR, xG, xB) (FLD_VAL(xR, 9, 0) | FLD_VAL(xG, 20, 11) |	\
245932a1795fSJyri Sarha 			  FLD_VAL(xB, 31, 22))
246032a1795fSJyri Sarha 
dispc_k2g_vp_csc_cpr_regval(const struct dispc_csc_coef * csc,u32 * regval)246132a1795fSJyri Sarha static void dispc_k2g_vp_csc_cpr_regval(const struct dispc_csc_coef *csc,
246232a1795fSJyri Sarha 					u32 *regval)
246332a1795fSJyri Sarha {
246432a1795fSJyri Sarha 	regval[0] = CVAL(csc->m[CSC_BB], csc->m[CSC_BG], csc->m[CSC_BR]);
246532a1795fSJyri Sarha 	regval[1] = CVAL(csc->m[CSC_GB], csc->m[CSC_GG], csc->m[CSC_GR]);
246632a1795fSJyri Sarha 	regval[2] = CVAL(csc->m[CSC_RB], csc->m[CSC_RG], csc->m[CSC_RR]);
246732a1795fSJyri Sarha }
246832a1795fSJyri Sarha 
246932a1795fSJyri Sarha #undef CVAL
247032a1795fSJyri Sarha 
dispc_k2g_vp_write_csc(struct dispc_device * dispc,u32 hw_videoport,const struct dispc_csc_coef * csc)247132a1795fSJyri Sarha static void dispc_k2g_vp_write_csc(struct dispc_device *dispc, u32 hw_videoport,
247232a1795fSJyri Sarha 				   const struct dispc_csc_coef *csc)
247332a1795fSJyri Sarha {
247432a1795fSJyri Sarha 	static const u16 dispc_vp_cpr_coef_reg[] = {
247532a1795fSJyri Sarha 		DISPC_VP_CSC_COEF0, DISPC_VP_CSC_COEF1, DISPC_VP_CSC_COEF2,
247632a1795fSJyri Sarha 		/* K2G CPR is packed to three registers. */
247732a1795fSJyri Sarha 	};
247832a1795fSJyri Sarha 	u32 regval[DISPC_CSC_REGVAL_LEN];
247932a1795fSJyri Sarha 	unsigned int i;
248032a1795fSJyri Sarha 
248132a1795fSJyri Sarha 	dispc_k2g_vp_csc_cpr_regval(csc, regval);
248232a1795fSJyri Sarha 
248332a1795fSJyri Sarha 	for (i = 0; i < ARRAY_SIZE(dispc_vp_cpr_coef_reg); i++)
248432a1795fSJyri Sarha 		dispc_vp_write(dispc, hw_videoport, dispc_vp_cpr_coef_reg[i],
248532a1795fSJyri Sarha 			       regval[i]);
248632a1795fSJyri Sarha }
248732a1795fSJyri Sarha 
dispc_k2g_vp_set_ctm(struct dispc_device * dispc,u32 hw_videoport,struct drm_color_ctm * ctm)248832a1795fSJyri Sarha static void dispc_k2g_vp_set_ctm(struct dispc_device *dispc, u32 hw_videoport,
248932a1795fSJyri Sarha 				 struct drm_color_ctm *ctm)
249032a1795fSJyri Sarha {
249132a1795fSJyri Sarha 	u32 cprenable = 0;
249232a1795fSJyri Sarha 
249332a1795fSJyri Sarha 	if (ctm) {
249432a1795fSJyri Sarha 		struct dispc_csc_coef cpr;
249532a1795fSJyri Sarha 
249632a1795fSJyri Sarha 		dispc_k2g_cpr_from_ctm(ctm, &cpr);
249732a1795fSJyri Sarha 		dispc_k2g_vp_write_csc(dispc, hw_videoport, &cpr);
249832a1795fSJyri Sarha 		cprenable = 1;
249932a1795fSJyri Sarha 	}
250032a1795fSJyri Sarha 
250132a1795fSJyri Sarha 	VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONFIG,
250232a1795fSJyri Sarha 		       cprenable, 15, 15);
250332a1795fSJyri Sarha }
250432a1795fSJyri Sarha 
dispc_S31_32_to_s3_8(s64 coef)250532a1795fSJyri Sarha static s16 dispc_S31_32_to_s3_8(s64 coef)
250632a1795fSJyri Sarha {
250732a1795fSJyri Sarha 	u64 sign_bit = 1ULL << 63;
250832a1795fSJyri Sarha 	u64 cbits = (u64)coef;
250932a1795fSJyri Sarha 	s16 ret;
251032a1795fSJyri Sarha 
251132a1795fSJyri Sarha 	if (cbits & sign_bit)
251232a1795fSJyri Sarha 		ret = -clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x400);
251332a1795fSJyri Sarha 	else
251432a1795fSJyri Sarha 		ret = clamp_val(((cbits & ~sign_bit) >> 24), 0, 0x3FF);
251532a1795fSJyri Sarha 
251632a1795fSJyri Sarha 	return ret;
251732a1795fSJyri Sarha }
251832a1795fSJyri Sarha 
dispc_csc_from_ctm(const struct drm_color_ctm * ctm,struct dispc_csc_coef * cpr)251932a1795fSJyri Sarha static void dispc_csc_from_ctm(const struct drm_color_ctm *ctm,
252032a1795fSJyri Sarha 			       struct dispc_csc_coef *cpr)
252132a1795fSJyri Sarha {
252232a1795fSJyri Sarha 	memset(cpr, 0, sizeof(*cpr));
252332a1795fSJyri Sarha 
252432a1795fSJyri Sarha 	cpr->to_regval = dispc_csc_cpr_regval;
252532a1795fSJyri Sarha 	cpr->m[CSC_RR] = dispc_S31_32_to_s3_8(ctm->matrix[0]);
252632a1795fSJyri Sarha 	cpr->m[CSC_RG] = dispc_S31_32_to_s3_8(ctm->matrix[1]);
252732a1795fSJyri Sarha 	cpr->m[CSC_RB] = dispc_S31_32_to_s3_8(ctm->matrix[2]);
252832a1795fSJyri Sarha 	cpr->m[CSC_GR] = dispc_S31_32_to_s3_8(ctm->matrix[3]);
252932a1795fSJyri Sarha 	cpr->m[CSC_GG] = dispc_S31_32_to_s3_8(ctm->matrix[4]);
253032a1795fSJyri Sarha 	cpr->m[CSC_GB] = dispc_S31_32_to_s3_8(ctm->matrix[5]);
253132a1795fSJyri Sarha 	cpr->m[CSC_BR] = dispc_S31_32_to_s3_8(ctm->matrix[6]);
253232a1795fSJyri Sarha 	cpr->m[CSC_BG] = dispc_S31_32_to_s3_8(ctm->matrix[7]);
253332a1795fSJyri Sarha 	cpr->m[CSC_BB] = dispc_S31_32_to_s3_8(ctm->matrix[8]);
253432a1795fSJyri Sarha }
253532a1795fSJyri Sarha 
dispc_k3_vp_write_csc(struct dispc_device * dispc,u32 hw_videoport,const struct dispc_csc_coef * csc)253632a1795fSJyri Sarha static void dispc_k3_vp_write_csc(struct dispc_device *dispc, u32 hw_videoport,
253732a1795fSJyri Sarha 				  const struct dispc_csc_coef *csc)
253832a1795fSJyri Sarha {
253932a1795fSJyri Sarha 	static const u16 dispc_vp_csc_coef_reg[DISPC_CSC_REGVAL_LEN] = {
254032a1795fSJyri Sarha 		DISPC_VP_CSC_COEF0, DISPC_VP_CSC_COEF1, DISPC_VP_CSC_COEF2,
254132a1795fSJyri Sarha 		DISPC_VP_CSC_COEF3, DISPC_VP_CSC_COEF4, DISPC_VP_CSC_COEF5,
254232a1795fSJyri Sarha 		DISPC_VP_CSC_COEF6, DISPC_VP_CSC_COEF7,
254332a1795fSJyri Sarha 	};
254432a1795fSJyri Sarha 	u32 regval[DISPC_CSC_REGVAL_LEN];
254532a1795fSJyri Sarha 	unsigned int i;
254632a1795fSJyri Sarha 
254732a1795fSJyri Sarha 	csc->to_regval(csc, regval);
254832a1795fSJyri Sarha 
254932a1795fSJyri Sarha 	for (i = 0; i < ARRAY_SIZE(regval); i++)
255032a1795fSJyri Sarha 		dispc_vp_write(dispc, hw_videoport, dispc_vp_csc_coef_reg[i],
255132a1795fSJyri Sarha 			       regval[i]);
255232a1795fSJyri Sarha }
255332a1795fSJyri Sarha 
dispc_k3_vp_set_ctm(struct dispc_device * dispc,u32 hw_videoport,struct drm_color_ctm * ctm)255432a1795fSJyri Sarha static void dispc_k3_vp_set_ctm(struct dispc_device *dispc, u32 hw_videoport,
255532a1795fSJyri Sarha 				struct drm_color_ctm *ctm)
255632a1795fSJyri Sarha {
255732a1795fSJyri Sarha 	u32 colorconvenable = 0;
255832a1795fSJyri Sarha 
255932a1795fSJyri Sarha 	if (ctm) {
256032a1795fSJyri Sarha 		struct dispc_csc_coef csc;
256132a1795fSJyri Sarha 
256232a1795fSJyri Sarha 		dispc_csc_from_ctm(ctm, &csc);
256332a1795fSJyri Sarha 		dispc_k3_vp_write_csc(dispc, hw_videoport, &csc);
256432a1795fSJyri Sarha 		colorconvenable = 1;
256532a1795fSJyri Sarha 	}
256632a1795fSJyri Sarha 
256732a1795fSJyri Sarha 	VP_REG_FLD_MOD(dispc, hw_videoport, DISPC_VP_CONFIG,
256832a1795fSJyri Sarha 		       colorconvenable, 24, 24);
256932a1795fSJyri Sarha }
257032a1795fSJyri Sarha 
dispc_vp_set_color_mgmt(struct dispc_device * dispc,u32 hw_videoport,const struct drm_crtc_state * state,bool newmodeset)257132a1795fSJyri Sarha static void dispc_vp_set_color_mgmt(struct dispc_device *dispc,
257232a1795fSJyri Sarha 				    u32 hw_videoport,
257332a1795fSJyri Sarha 				    const struct drm_crtc_state *state,
257432a1795fSJyri Sarha 				    bool newmodeset)
257532a1795fSJyri Sarha {
257632a1795fSJyri Sarha 	struct drm_color_lut *lut = NULL;
257732a1795fSJyri Sarha 	struct drm_color_ctm *ctm = NULL;
257832a1795fSJyri Sarha 	unsigned int length = 0;
257932a1795fSJyri Sarha 
258032a1795fSJyri Sarha 	if (!(state->color_mgmt_changed || newmodeset))
258132a1795fSJyri Sarha 		return;
258232a1795fSJyri Sarha 
258332a1795fSJyri Sarha 	if (state->gamma_lut) {
258432a1795fSJyri Sarha 		lut = (struct drm_color_lut *)state->gamma_lut->data;
258532a1795fSJyri Sarha 		length = state->gamma_lut->length / sizeof(*lut);
258632a1795fSJyri Sarha 	}
258732a1795fSJyri Sarha 
258832a1795fSJyri Sarha 	dispc_vp_set_gamma(dispc, hw_videoport, lut, length);
258932a1795fSJyri Sarha 
259032a1795fSJyri Sarha 	if (state->ctm)
259132a1795fSJyri Sarha 		ctm = (struct drm_color_ctm *)state->ctm->data;
259232a1795fSJyri Sarha 
259332a1795fSJyri Sarha 	if (dispc->feat->subrev == DISPC_K2G)
259432a1795fSJyri Sarha 		dispc_k2g_vp_set_ctm(dispc, hw_videoport, ctm);
259532a1795fSJyri Sarha 	else
259632a1795fSJyri Sarha 		dispc_k3_vp_set_ctm(dispc, hw_videoport, ctm);
259732a1795fSJyri Sarha }
259832a1795fSJyri Sarha 
dispc_vp_setup(struct dispc_device * dispc,u32 hw_videoport,const struct drm_crtc_state * state,bool newmodeset)259932a1795fSJyri Sarha void dispc_vp_setup(struct dispc_device *dispc, u32 hw_videoport,
260032a1795fSJyri Sarha 		    const struct drm_crtc_state *state, bool newmodeset)
260132a1795fSJyri Sarha {
260232a1795fSJyri Sarha 	dispc_vp_set_default_color(dispc, hw_videoport, 0);
260332a1795fSJyri Sarha 	dispc_vp_set_color_mgmt(dispc, hw_videoport, state, newmodeset);
260432a1795fSJyri Sarha }
260532a1795fSJyri Sarha 
dispc_runtime_suspend(struct dispc_device * dispc)260632a1795fSJyri Sarha int dispc_runtime_suspend(struct dispc_device *dispc)
260732a1795fSJyri Sarha {
260832a1795fSJyri Sarha 	dev_dbg(dispc->dev, "suspend\n");
260932a1795fSJyri Sarha 
261032a1795fSJyri Sarha 	dispc->is_enabled = false;
261132a1795fSJyri Sarha 
261232a1795fSJyri Sarha 	clk_disable_unprepare(dispc->fclk);
261332a1795fSJyri Sarha 
261432a1795fSJyri Sarha 	return 0;
261532a1795fSJyri Sarha }
261632a1795fSJyri Sarha 
dispc_runtime_resume(struct dispc_device * dispc)261732a1795fSJyri Sarha int dispc_runtime_resume(struct dispc_device *dispc)
261832a1795fSJyri Sarha {
261932a1795fSJyri Sarha 	dev_dbg(dispc->dev, "resume\n");
262032a1795fSJyri Sarha 
262132a1795fSJyri Sarha 	clk_prepare_enable(dispc->fclk);
262232a1795fSJyri Sarha 
262332a1795fSJyri Sarha 	if (REG_GET(dispc, DSS_SYSSTATUS, 0, 0) == 0)
262432a1795fSJyri Sarha 		dev_warn(dispc->dev, "DSS FUNC RESET not done!\n");
262532a1795fSJyri Sarha 
262632a1795fSJyri Sarha 	dev_dbg(dispc->dev, "OMAP DSS7 rev 0x%x\n",
262732a1795fSJyri Sarha 		dispc_read(dispc, DSS_REVISION));
262832a1795fSJyri Sarha 
262932a1795fSJyri Sarha 	dev_dbg(dispc->dev, "VP RESETDONE %d,%d,%d\n",
263032a1795fSJyri Sarha 		REG_GET(dispc, DSS_SYSSTATUS, 1, 1),
263132a1795fSJyri Sarha 		REG_GET(dispc, DSS_SYSSTATUS, 2, 2),
263232a1795fSJyri Sarha 		REG_GET(dispc, DSS_SYSSTATUS, 3, 3));
263332a1795fSJyri Sarha 
2634ad2ac9dcSAradhya Bhatia 	if (dispc->feat->subrev == DISPC_AM625 ||
2635ad2ac9dcSAradhya Bhatia 	    dispc->feat->subrev == DISPC_AM65X)
263632a1795fSJyri Sarha 		dev_dbg(dispc->dev, "OLDI RESETDONE %d,%d,%d\n",
263732a1795fSJyri Sarha 			REG_GET(dispc, DSS_SYSSTATUS, 5, 5),
263832a1795fSJyri Sarha 			REG_GET(dispc, DSS_SYSSTATUS, 6, 6),
263932a1795fSJyri Sarha 			REG_GET(dispc, DSS_SYSSTATUS, 7, 7));
264032a1795fSJyri Sarha 
264132a1795fSJyri Sarha 	dev_dbg(dispc->dev, "DISPC IDLE %d\n",
264232a1795fSJyri Sarha 		REG_GET(dispc, DSS_SYSSTATUS, 9, 9));
264332a1795fSJyri Sarha 
264432a1795fSJyri Sarha 	dispc_initial_config(dispc);
264532a1795fSJyri Sarha 
264632a1795fSJyri Sarha 	dispc->is_enabled = true;
264732a1795fSJyri Sarha 
264832a1795fSJyri Sarha 	tidss_irq_resume(dispc->tidss);
264932a1795fSJyri Sarha 
265032a1795fSJyri Sarha 	return 0;
265132a1795fSJyri Sarha }
265232a1795fSJyri Sarha 
dispc_remove(struct tidss_device * tidss)265332a1795fSJyri Sarha void dispc_remove(struct tidss_device *tidss)
265432a1795fSJyri Sarha {
265532a1795fSJyri Sarha 	dev_dbg(tidss->dev, "%s\n", __func__);
265632a1795fSJyri Sarha 
265732a1795fSJyri Sarha 	tidss->dispc = NULL;
265832a1795fSJyri Sarha }
265932a1795fSJyri Sarha 
dispc_iomap_resource(struct platform_device * pdev,const char * name,void __iomem ** base)266032a1795fSJyri Sarha static int dispc_iomap_resource(struct platform_device *pdev, const char *name,
266132a1795fSJyri Sarha 				void __iomem **base)
266232a1795fSJyri Sarha {
266332a1795fSJyri Sarha 	void __iomem *b;
266432a1795fSJyri Sarha 
26653945ac0eSWang Xiaojun 	b = devm_platform_ioremap_resource_byname(pdev, name);
266632a1795fSJyri Sarha 	if (IS_ERR(b)) {
266732a1795fSJyri Sarha 		dev_err(&pdev->dev, "cannot ioremap resource '%s'\n", name);
266832a1795fSJyri Sarha 		return PTR_ERR(b);
266932a1795fSJyri Sarha 	}
267032a1795fSJyri Sarha 
267132a1795fSJyri Sarha 	*base = b;
267232a1795fSJyri Sarha 
267332a1795fSJyri Sarha 	return 0;
267432a1795fSJyri Sarha }
267532a1795fSJyri Sarha 
dispc_init_am65x_oldi_io_ctrl(struct device * dev,struct dispc_device * dispc)267632a1795fSJyri Sarha static int dispc_init_am65x_oldi_io_ctrl(struct device *dev,
267732a1795fSJyri Sarha 					 struct dispc_device *dispc)
267832a1795fSJyri Sarha {
267932a1795fSJyri Sarha 	dispc->oldi_io_ctrl =
268032a1795fSJyri Sarha 		syscon_regmap_lookup_by_phandle(dev->of_node,
268132a1795fSJyri Sarha 						"ti,am65x-oldi-io-ctrl");
268232a1795fSJyri Sarha 	if (PTR_ERR(dispc->oldi_io_ctrl) == -ENODEV) {
268332a1795fSJyri Sarha 		dispc->oldi_io_ctrl = NULL;
268432a1795fSJyri Sarha 	} else if (IS_ERR(dispc->oldi_io_ctrl)) {
268532a1795fSJyri Sarha 		dev_err(dev, "%s: syscon_regmap_lookup_by_phandle failed %ld\n",
268632a1795fSJyri Sarha 			__func__, PTR_ERR(dispc->oldi_io_ctrl));
268732a1795fSJyri Sarha 		return PTR_ERR(dispc->oldi_io_ctrl);
268832a1795fSJyri Sarha 	}
268932a1795fSJyri Sarha 	return 0;
269032a1795fSJyri Sarha }
269132a1795fSJyri Sarha 
dispc_init_errata(struct dispc_device * dispc)26928b87014fSTomi Valkeinen static void dispc_init_errata(struct dispc_device *dispc)
26938b87014fSTomi Valkeinen {
26948b87014fSTomi Valkeinen 	static const struct soc_device_attribute am65x_sr10_soc_devices[] = {
26958b87014fSTomi Valkeinen 		{ .family = "AM65X", .revision = "SR1.0" },
26968b87014fSTomi Valkeinen 		{ /* sentinel */ }
26978b87014fSTomi Valkeinen 	};
26988b87014fSTomi Valkeinen 
26998b87014fSTomi Valkeinen 	if (soc_device_match(am65x_sr10_soc_devices)) {
27008b87014fSTomi Valkeinen 		dispc->errata.i2000 = true;
27018b87014fSTomi Valkeinen 		dev_info(dispc->dev, "WA for erratum i2000: YUV formats disabled\n");
27028b87014fSTomi Valkeinen 	}
27038b87014fSTomi Valkeinen }
27048b87014fSTomi Valkeinen 
dispc_softreset(struct dispc_device * dispc)27054fcfe757STomi Valkeinen static int dispc_softreset(struct dispc_device *dispc)
2706c9b2d923SDevarsh Thakkar {
2707c9b2d923SDevarsh Thakkar 	u32 val;
2708c9b2d923SDevarsh Thakkar 	int ret = 0;
2709c9b2d923SDevarsh Thakkar 
271011e2dc2fSTomi Valkeinen 	/* K2G display controller does not support soft reset */
271111e2dc2fSTomi Valkeinen 	if (dispc->feat->subrev == DISPC_K2G)
271211e2dc2fSTomi Valkeinen 		return 0;
271311e2dc2fSTomi Valkeinen 
2714c9b2d923SDevarsh Thakkar 	/* Soft reset */
2715c9b2d923SDevarsh Thakkar 	REG_FLD_MOD(dispc, DSS_SYSCONFIG, 1, 1, 1);
2716c9b2d923SDevarsh Thakkar 	/* Wait for reset to complete */
2717c9b2d923SDevarsh Thakkar 	ret = readl_poll_timeout(dispc->base_common + DSS_SYSSTATUS,
2718c9b2d923SDevarsh Thakkar 				 val, val & 1, 100, 5000);
27194fcfe757STomi Valkeinen 	if (ret) {
27204fcfe757STomi Valkeinen 		dev_err(dispc->dev, "failed to reset dispc\n");
27214fcfe757STomi Valkeinen 		return ret;
27224fcfe757STomi Valkeinen 	}
27234fcfe757STomi Valkeinen 
27244fcfe757STomi Valkeinen 	return 0;
2725c9b2d923SDevarsh Thakkar }
2726c9b2d923SDevarsh Thakkar 
dispc_init_hw(struct dispc_device * dispc)2727*417d134eSTomi Valkeinen static int dispc_init_hw(struct dispc_device *dispc)
2728*417d134eSTomi Valkeinen {
2729*417d134eSTomi Valkeinen 	struct device *dev = dispc->dev;
2730*417d134eSTomi Valkeinen 	int ret;
2731*417d134eSTomi Valkeinen 
2732*417d134eSTomi Valkeinen 	ret = pm_runtime_set_active(dev);
2733*417d134eSTomi Valkeinen 	if (ret) {
2734*417d134eSTomi Valkeinen 		dev_err(dev, "Failed to set DSS PM to active\n");
2735*417d134eSTomi Valkeinen 		return ret;
2736*417d134eSTomi Valkeinen 	}
2737*417d134eSTomi Valkeinen 
2738*417d134eSTomi Valkeinen 	ret = clk_prepare_enable(dispc->fclk);
2739*417d134eSTomi Valkeinen 	if (ret) {
2740*417d134eSTomi Valkeinen 		dev_err(dev, "Failed to enable DSS fclk\n");
2741*417d134eSTomi Valkeinen 		goto err_runtime_suspend;
2742*417d134eSTomi Valkeinen 	}
2743*417d134eSTomi Valkeinen 
2744*417d134eSTomi Valkeinen 	ret = dispc_softreset(dispc);
2745*417d134eSTomi Valkeinen 	if (ret)
2746*417d134eSTomi Valkeinen 		goto err_clk_disable;
2747*417d134eSTomi Valkeinen 
2748*417d134eSTomi Valkeinen 	clk_disable_unprepare(dispc->fclk);
2749*417d134eSTomi Valkeinen 	ret = pm_runtime_set_suspended(dev);
2750*417d134eSTomi Valkeinen 	if (ret) {
2751*417d134eSTomi Valkeinen 		dev_err(dev, "Failed to set DSS PM to suspended\n");
2752*417d134eSTomi Valkeinen 		return ret;
2753*417d134eSTomi Valkeinen 	}
2754*417d134eSTomi Valkeinen 
2755*417d134eSTomi Valkeinen 	return 0;
2756*417d134eSTomi Valkeinen 
2757*417d134eSTomi Valkeinen err_clk_disable:
2758*417d134eSTomi Valkeinen 	clk_disable_unprepare(dispc->fclk);
2759*417d134eSTomi Valkeinen 
2760*417d134eSTomi Valkeinen err_runtime_suspend:
2761*417d134eSTomi Valkeinen 	ret = pm_runtime_set_suspended(dev);
2762*417d134eSTomi Valkeinen 	if (ret) {
2763*417d134eSTomi Valkeinen 		dev_err(dev, "Failed to set DSS PM to suspended\n");
2764*417d134eSTomi Valkeinen 		return ret;
2765*417d134eSTomi Valkeinen 	}
2766*417d134eSTomi Valkeinen 
2767*417d134eSTomi Valkeinen 	return ret;
2768*417d134eSTomi Valkeinen }
2769*417d134eSTomi Valkeinen 
dispc_init(struct tidss_device * tidss)277032a1795fSJyri Sarha int dispc_init(struct tidss_device *tidss)
277132a1795fSJyri Sarha {
277232a1795fSJyri Sarha 	struct device *dev = tidss->dev;
277332a1795fSJyri Sarha 	struct platform_device *pdev = to_platform_device(dev);
277432a1795fSJyri Sarha 	struct dispc_device *dispc;
277532a1795fSJyri Sarha 	const struct dispc_features *feat;
277632a1795fSJyri Sarha 	unsigned int i, num_fourccs;
277732a1795fSJyri Sarha 	int r = 0;
277832a1795fSJyri Sarha 
277932a1795fSJyri Sarha 	dev_dbg(dev, "%s\n", __func__);
278032a1795fSJyri Sarha 
278132a1795fSJyri Sarha 	feat = tidss->feat;
278232a1795fSJyri Sarha 
278332a1795fSJyri Sarha 	if (feat->subrev != DISPC_K2G) {
278432a1795fSJyri Sarha 		r = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
278532a1795fSJyri Sarha 		if (r)
278632a1795fSJyri Sarha 			dev_warn(dev, "cannot set DMA masks to 48-bit\n");
278732a1795fSJyri Sarha 	}
278832a1795fSJyri Sarha 
278985528a44SAndrew Davis 	dma_set_max_seg_size(dev, UINT_MAX);
279085528a44SAndrew Davis 
279132a1795fSJyri Sarha 	dispc = devm_kzalloc(dev, sizeof(*dispc), GFP_KERNEL);
279232a1795fSJyri Sarha 	if (!dispc)
279332a1795fSJyri Sarha 		return -ENOMEM;
279432a1795fSJyri Sarha 
27958b87014fSTomi Valkeinen 	dispc->tidss = tidss;
27968b87014fSTomi Valkeinen 	dispc->dev = dev;
27978b87014fSTomi Valkeinen 	dispc->feat = feat;
27988b87014fSTomi Valkeinen 
27998b87014fSTomi Valkeinen 	dispc_init_errata(dispc);
28008b87014fSTomi Valkeinen 
280132a1795fSJyri Sarha 	dispc->fourccs = devm_kcalloc(dev, ARRAY_SIZE(dispc_color_formats),
280232a1795fSJyri Sarha 				      sizeof(*dispc->fourccs), GFP_KERNEL);
280332a1795fSJyri Sarha 	if (!dispc->fourccs)
280432a1795fSJyri Sarha 		return -ENOMEM;
280532a1795fSJyri Sarha 
280632a1795fSJyri Sarha 	num_fourccs = 0;
28078b87014fSTomi Valkeinen 	for (i = 0; i < ARRAY_SIZE(dispc_color_formats); ++i) {
28088b87014fSTomi Valkeinen 		if (dispc->errata.i2000 &&
28098b87014fSTomi Valkeinen 		    dispc_fourcc_is_yuv(dispc_color_formats[i].fourcc)) {
28108b87014fSTomi Valkeinen 			continue;
28118b87014fSTomi Valkeinen 		}
281232a1795fSJyri Sarha 		dispc->fourccs[num_fourccs++] = dispc_color_formats[i].fourcc;
28138b87014fSTomi Valkeinen 	}
2814a8d9d7daSTomi Valkeinen 
281532a1795fSJyri Sarha 	dispc->num_fourccs = num_fourccs;
281632a1795fSJyri Sarha 
281732a1795fSJyri Sarha 	dispc_common_regmap = dispc->feat->common_regs;
281832a1795fSJyri Sarha 
281932a1795fSJyri Sarha 	r = dispc_iomap_resource(pdev, dispc->feat->common,
282032a1795fSJyri Sarha 				 &dispc->base_common);
282132a1795fSJyri Sarha 	if (r)
282232a1795fSJyri Sarha 		return r;
282332a1795fSJyri Sarha 
282432a1795fSJyri Sarha 	for (i = 0; i < dispc->feat->num_planes; i++) {
282532a1795fSJyri Sarha 		r = dispc_iomap_resource(pdev, dispc->feat->vid_name[i],
282632a1795fSJyri Sarha 					 &dispc->base_vid[i]);
282732a1795fSJyri Sarha 		if (r)
282832a1795fSJyri Sarha 			return r;
282932a1795fSJyri Sarha 	}
283032a1795fSJyri Sarha 
283132a1795fSJyri Sarha 	for (i = 0; i < dispc->feat->num_vps; i++) {
283232a1795fSJyri Sarha 		u32 gamma_size = dispc->feat->vp_feat.color.gamma_size;
283332a1795fSJyri Sarha 		u32 *gamma_table;
283432a1795fSJyri Sarha 		struct clk *clk;
283532a1795fSJyri Sarha 
283632a1795fSJyri Sarha 		r = dispc_iomap_resource(pdev, dispc->feat->ovr_name[i],
283732a1795fSJyri Sarha 					 &dispc->base_ovr[i]);
283832a1795fSJyri Sarha 		if (r)
283932a1795fSJyri Sarha 			return r;
284032a1795fSJyri Sarha 
284132a1795fSJyri Sarha 		r = dispc_iomap_resource(pdev, dispc->feat->vp_name[i],
284232a1795fSJyri Sarha 					 &dispc->base_vp[i]);
284332a1795fSJyri Sarha 		if (r)
284432a1795fSJyri Sarha 			return r;
284532a1795fSJyri Sarha 
284632a1795fSJyri Sarha 		clk = devm_clk_get(dev, dispc->feat->vpclk_name[i]);
284732a1795fSJyri Sarha 		if (IS_ERR(clk)) {
284832a1795fSJyri Sarha 			dev_err(dev, "%s: Failed to get clk %s:%ld\n", __func__,
284932a1795fSJyri Sarha 				dispc->feat->vpclk_name[i], PTR_ERR(clk));
285032a1795fSJyri Sarha 			return PTR_ERR(clk);
285132a1795fSJyri Sarha 		}
285232a1795fSJyri Sarha 		dispc->vp_clk[i] = clk;
285332a1795fSJyri Sarha 
285432a1795fSJyri Sarha 		gamma_table = devm_kmalloc_array(dev, gamma_size,
285532a1795fSJyri Sarha 						 sizeof(*gamma_table),
285632a1795fSJyri Sarha 						 GFP_KERNEL);
285732a1795fSJyri Sarha 		if (!gamma_table)
285832a1795fSJyri Sarha 			return -ENOMEM;
285932a1795fSJyri Sarha 		dispc->vp_data[i].gamma_table = gamma_table;
286032a1795fSJyri Sarha 	}
286132a1795fSJyri Sarha 
286232a1795fSJyri Sarha 	if (feat->subrev == DISPC_AM65X) {
286332a1795fSJyri Sarha 		r = dispc_init_am65x_oldi_io_ctrl(dev, dispc);
286432a1795fSJyri Sarha 		if (r)
286532a1795fSJyri Sarha 			return r;
286632a1795fSJyri Sarha 	}
286732a1795fSJyri Sarha 
286832a1795fSJyri Sarha 	dispc->fclk = devm_clk_get(dev, "fck");
286932a1795fSJyri Sarha 	if (IS_ERR(dispc->fclk)) {
287032a1795fSJyri Sarha 		dev_err(dev, "%s: Failed to get fclk: %ld\n",
287132a1795fSJyri Sarha 			__func__, PTR_ERR(dispc->fclk));
287232a1795fSJyri Sarha 		return PTR_ERR(dispc->fclk);
287332a1795fSJyri Sarha 	}
287432a1795fSJyri Sarha 	dev_dbg(dev, "DSS fclk %lu Hz\n", clk_get_rate(dispc->fclk));
287532a1795fSJyri Sarha 
287632a1795fSJyri Sarha 	of_property_read_u32(dispc->dev->of_node, "max-memory-bandwidth",
287732a1795fSJyri Sarha 			     &dispc->memory_bandwidth_limit);
287832a1795fSJyri Sarha 
2879*417d134eSTomi Valkeinen 	r = dispc_init_hw(dispc);
28804fcfe757STomi Valkeinen 	if (r)
28814fcfe757STomi Valkeinen 		return r;
2882d44143cdSTomi Valkeinen 
288332a1795fSJyri Sarha 	tidss->dispc = dispc;
288432a1795fSJyri Sarha 
288532a1795fSJyri Sarha 	return 0;
288632a1795fSJyri Sarha }
2887