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