162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2009 Nokia Corporation
462306a36Sopenharmony_ci * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Some code and ideas taken from drivers/video/omap/ driver
762306a36Sopenharmony_ci * by Imre Deak.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define DSS_SUBSYS_NAME "DISPC"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1462306a36Sopenharmony_ci#include <linux/vmalloc.h>
1562306a36Sopenharmony_ci#include <linux/export.h>
1662306a36Sopenharmony_ci#include <linux/clk.h>
1762306a36Sopenharmony_ci#include <linux/io.h>
1862306a36Sopenharmony_ci#include <linux/jiffies.h>
1962306a36Sopenharmony_ci#include <linux/seq_file.h>
2062306a36Sopenharmony_ci#include <linux/delay.h>
2162306a36Sopenharmony_ci#include <linux/workqueue.h>
2262306a36Sopenharmony_ci#include <linux/hardirq.h>
2362306a36Sopenharmony_ci#include <linux/platform_device.h>
2462306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2562306a36Sopenharmony_ci#include <linux/sizes.h>
2662306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
2762306a36Sopenharmony_ci#include <linux/regmap.h>
2862306a36Sopenharmony_ci#include <linux/of.h>
2962306a36Sopenharmony_ci#include <linux/of_device.h>
3062306a36Sopenharmony_ci#include <linux/component.h>
3162306a36Sopenharmony_ci#include <linux/sys_soc.h>
3262306a36Sopenharmony_ci#include <drm/drm_fourcc.h>
3362306a36Sopenharmony_ci#include <drm/drm_blend.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include "omapdss.h"
3662306a36Sopenharmony_ci#include "dss.h"
3762306a36Sopenharmony_ci#include "dispc.h"
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistruct dispc_device;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/* DISPC */
4262306a36Sopenharmony_ci#define DISPC_SZ_REGS			SZ_4K
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cienum omap_burst_size {
4562306a36Sopenharmony_ci	BURST_SIZE_X2 = 0,
4662306a36Sopenharmony_ci	BURST_SIZE_X4 = 1,
4762306a36Sopenharmony_ci	BURST_SIZE_X8 = 2,
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define REG_GET(dispc, idx, start, end) \
5162306a36Sopenharmony_ci	FLD_GET(dispc_read_reg(dispc, idx), start, end)
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define REG_FLD_MOD(dispc, idx, val, start, end)			\
5462306a36Sopenharmony_ci	dispc_write_reg(dispc, idx, \
5562306a36Sopenharmony_ci			FLD_MOD(dispc_read_reg(dispc, idx), val, start, end))
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* DISPC has feature id */
5862306a36Sopenharmony_cienum dispc_feature_id {
5962306a36Sopenharmony_ci	FEAT_LCDENABLEPOL,
6062306a36Sopenharmony_ci	FEAT_LCDENABLESIGNAL,
6162306a36Sopenharmony_ci	FEAT_PCKFREEENABLE,
6262306a36Sopenharmony_ci	FEAT_FUNCGATED,
6362306a36Sopenharmony_ci	FEAT_MGR_LCD2,
6462306a36Sopenharmony_ci	FEAT_MGR_LCD3,
6562306a36Sopenharmony_ci	FEAT_LINEBUFFERSPLIT,
6662306a36Sopenharmony_ci	FEAT_ROWREPEATENABLE,
6762306a36Sopenharmony_ci	FEAT_RESIZECONF,
6862306a36Sopenharmony_ci	/* Independent core clk divider */
6962306a36Sopenharmony_ci	FEAT_CORE_CLK_DIV,
7062306a36Sopenharmony_ci	FEAT_HANDLE_UV_SEPARATE,
7162306a36Sopenharmony_ci	FEAT_ATTR2,
7262306a36Sopenharmony_ci	FEAT_CPR,
7362306a36Sopenharmony_ci	FEAT_PRELOAD,
7462306a36Sopenharmony_ci	FEAT_FIR_COEF_V,
7562306a36Sopenharmony_ci	FEAT_ALPHA_FIXED_ZORDER,
7662306a36Sopenharmony_ci	FEAT_ALPHA_FREE_ZORDER,
7762306a36Sopenharmony_ci	FEAT_FIFO_MERGE,
7862306a36Sopenharmony_ci	/* An unknown HW bug causing the normal FIFO thresholds not to work */
7962306a36Sopenharmony_ci	FEAT_OMAP3_DSI_FIFO_BUG,
8062306a36Sopenharmony_ci	FEAT_BURST_2D,
8162306a36Sopenharmony_ci	FEAT_MFLAG,
8262306a36Sopenharmony_ci};
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistruct dispc_features {
8562306a36Sopenharmony_ci	u8 sw_start;
8662306a36Sopenharmony_ci	u8 fp_start;
8762306a36Sopenharmony_ci	u8 bp_start;
8862306a36Sopenharmony_ci	u16 sw_max;
8962306a36Sopenharmony_ci	u16 vp_max;
9062306a36Sopenharmony_ci	u16 hp_max;
9162306a36Sopenharmony_ci	u8 mgr_width_start;
9262306a36Sopenharmony_ci	u8 mgr_height_start;
9362306a36Sopenharmony_ci	u16 mgr_width_max;
9462306a36Sopenharmony_ci	u16 mgr_height_max;
9562306a36Sopenharmony_ci	u16 ovl_width_max;
9662306a36Sopenharmony_ci	u16 ovl_height_max;
9762306a36Sopenharmony_ci	unsigned long max_lcd_pclk;
9862306a36Sopenharmony_ci	unsigned long max_tv_pclk;
9962306a36Sopenharmony_ci	unsigned int max_downscale;
10062306a36Sopenharmony_ci	unsigned int max_line_width;
10162306a36Sopenharmony_ci	unsigned int min_pcd;
10262306a36Sopenharmony_ci	int (*calc_scaling)(struct dispc_device *dispc,
10362306a36Sopenharmony_ci		unsigned long pclk, unsigned long lclk,
10462306a36Sopenharmony_ci		const struct videomode *vm,
10562306a36Sopenharmony_ci		u16 width, u16 height, u16 out_width, u16 out_height,
10662306a36Sopenharmony_ci		u32 fourcc, bool *five_taps,
10762306a36Sopenharmony_ci		int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
10862306a36Sopenharmony_ci		u16 pos_x, unsigned long *core_clk, bool mem_to_mem);
10962306a36Sopenharmony_ci	unsigned long (*calc_core_clk) (unsigned long pclk,
11062306a36Sopenharmony_ci		u16 width, u16 height, u16 out_width, u16 out_height,
11162306a36Sopenharmony_ci		bool mem_to_mem);
11262306a36Sopenharmony_ci	u8 num_fifos;
11362306a36Sopenharmony_ci	const enum dispc_feature_id *features;
11462306a36Sopenharmony_ci	unsigned int num_features;
11562306a36Sopenharmony_ci	const struct dss_reg_field *reg_fields;
11662306a36Sopenharmony_ci	const unsigned int num_reg_fields;
11762306a36Sopenharmony_ci	const enum omap_overlay_caps *overlay_caps;
11862306a36Sopenharmony_ci	const u32 **supported_color_modes;
11962306a36Sopenharmony_ci	const u32 *supported_scaler_color_modes;
12062306a36Sopenharmony_ci	unsigned int num_mgrs;
12162306a36Sopenharmony_ci	unsigned int num_ovls;
12262306a36Sopenharmony_ci	unsigned int buffer_size_unit;
12362306a36Sopenharmony_ci	unsigned int burst_size_unit;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	/* swap GFX & WB fifos */
12662306a36Sopenharmony_ci	bool gfx_fifo_workaround:1;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	/* no DISPC_IRQ_FRAMEDONETV on this SoC */
12962306a36Sopenharmony_ci	bool no_framedone_tv:1;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	/* revert to the OMAP4 mechanism of DISPC Smart Standby operation */
13262306a36Sopenharmony_ci	bool mstandby_workaround:1;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	bool set_max_preload:1;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/* PIXEL_INC is not added to the last pixel of a line */
13762306a36Sopenharmony_ci	bool last_pixel_inc_missing:1;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	/* POL_FREQ has ALIGN bit */
14062306a36Sopenharmony_ci	bool supports_sync_align:1;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	bool has_writeback:1;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	bool supports_double_pixel:1;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/*
14762306a36Sopenharmony_ci	 * Field order for VENC is different than HDMI. We should handle this in
14862306a36Sopenharmony_ci	 * some intelligent manner, but as the SoCs have either HDMI or VENC,
14962306a36Sopenharmony_ci	 * never both, we can just use this flag for now.
15062306a36Sopenharmony_ci	 */
15162306a36Sopenharmony_ci	bool reverse_ilace_field_order:1;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	bool has_gamma_table:1;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	bool has_gamma_i734_bug:1;
15662306a36Sopenharmony_ci};
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci#define DISPC_MAX_NR_FIFOS 5
15962306a36Sopenharmony_ci#define DISPC_MAX_CHANNEL_GAMMA 4
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistruct dispc_device {
16262306a36Sopenharmony_ci	struct platform_device *pdev;
16362306a36Sopenharmony_ci	void __iomem    *base;
16462306a36Sopenharmony_ci	struct dss_device *dss;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	struct dss_debugfs_entry *debugfs;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	int irq;
16962306a36Sopenharmony_ci	irq_handler_t user_handler;
17062306a36Sopenharmony_ci	void *user_data;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	unsigned long core_clk_rate;
17362306a36Sopenharmony_ci	unsigned long tv_pclk_rate;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	u32 fifo_size[DISPC_MAX_NR_FIFOS];
17662306a36Sopenharmony_ci	/* maps which plane is using a fifo. fifo-id -> plane-id */
17762306a36Sopenharmony_ci	int fifo_assignment[DISPC_MAX_NR_FIFOS];
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	bool		ctx_valid;
18062306a36Sopenharmony_ci	u32		ctx[DISPC_SZ_REGS / sizeof(u32)];
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	u32 *gamma_table[DISPC_MAX_CHANNEL_GAMMA];
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	const struct dispc_features *feat;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	bool is_enabled;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	struct regmap *syscon_pol;
18962306a36Sopenharmony_ci	u32 syscon_pol_offset;
19062306a36Sopenharmony_ci};
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cienum omap_color_component {
19362306a36Sopenharmony_ci	/* used for all color formats for OMAP3 and earlier
19462306a36Sopenharmony_ci	 * and for RGB and Y color component on OMAP4
19562306a36Sopenharmony_ci	 */
19662306a36Sopenharmony_ci	DISPC_COLOR_COMPONENT_RGB_Y		= 1 << 0,
19762306a36Sopenharmony_ci	/* used for UV component for
19862306a36Sopenharmony_ci	 * DRM_FORMAT_YUYV, DRM_FORMAT_UYVY, DRM_FORMAT_NV12
19962306a36Sopenharmony_ci	 * color formats on OMAP4
20062306a36Sopenharmony_ci	 */
20162306a36Sopenharmony_ci	DISPC_COLOR_COMPONENT_UV		= 1 << 1,
20262306a36Sopenharmony_ci};
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cienum mgr_reg_fields {
20562306a36Sopenharmony_ci	DISPC_MGR_FLD_ENABLE,
20662306a36Sopenharmony_ci	DISPC_MGR_FLD_STNTFT,
20762306a36Sopenharmony_ci	DISPC_MGR_FLD_GO,
20862306a36Sopenharmony_ci	DISPC_MGR_FLD_TFTDATALINES,
20962306a36Sopenharmony_ci	DISPC_MGR_FLD_STALLMODE,
21062306a36Sopenharmony_ci	DISPC_MGR_FLD_TCKENABLE,
21162306a36Sopenharmony_ci	DISPC_MGR_FLD_TCKSELECTION,
21262306a36Sopenharmony_ci	DISPC_MGR_FLD_CPR,
21362306a36Sopenharmony_ci	DISPC_MGR_FLD_FIFOHANDCHECK,
21462306a36Sopenharmony_ci	/* used to maintain a count of the above fields */
21562306a36Sopenharmony_ci	DISPC_MGR_FLD_NUM,
21662306a36Sopenharmony_ci};
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci/* DISPC register field id */
21962306a36Sopenharmony_cienum dispc_feat_reg_field {
22062306a36Sopenharmony_ci	FEAT_REG_FIRHINC,
22162306a36Sopenharmony_ci	FEAT_REG_FIRVINC,
22262306a36Sopenharmony_ci	FEAT_REG_FIFOHIGHTHRESHOLD,
22362306a36Sopenharmony_ci	FEAT_REG_FIFOLOWTHRESHOLD,
22462306a36Sopenharmony_ci	FEAT_REG_FIFOSIZE,
22562306a36Sopenharmony_ci	FEAT_REG_HORIZONTALACCU,
22662306a36Sopenharmony_ci	FEAT_REG_VERTICALACCU,
22762306a36Sopenharmony_ci};
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistruct dispc_reg_field {
23062306a36Sopenharmony_ci	u16 reg;
23162306a36Sopenharmony_ci	u8 high;
23262306a36Sopenharmony_ci	u8 low;
23362306a36Sopenharmony_ci};
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistruct dispc_gamma_desc {
23662306a36Sopenharmony_ci	u32 len;
23762306a36Sopenharmony_ci	u32 bits;
23862306a36Sopenharmony_ci	u16 reg;
23962306a36Sopenharmony_ci	bool has_index;
24062306a36Sopenharmony_ci};
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic const struct {
24362306a36Sopenharmony_ci	const char *name;
24462306a36Sopenharmony_ci	u32 vsync_irq;
24562306a36Sopenharmony_ci	u32 framedone_irq;
24662306a36Sopenharmony_ci	u32 sync_lost_irq;
24762306a36Sopenharmony_ci	struct dispc_gamma_desc gamma;
24862306a36Sopenharmony_ci	struct dispc_reg_field reg_desc[DISPC_MGR_FLD_NUM];
24962306a36Sopenharmony_ci} mgr_desc[] = {
25062306a36Sopenharmony_ci	[OMAP_DSS_CHANNEL_LCD] = {
25162306a36Sopenharmony_ci		.name		= "LCD",
25262306a36Sopenharmony_ci		.vsync_irq	= DISPC_IRQ_VSYNC,
25362306a36Sopenharmony_ci		.framedone_irq	= DISPC_IRQ_FRAMEDONE,
25462306a36Sopenharmony_ci		.sync_lost_irq	= DISPC_IRQ_SYNC_LOST,
25562306a36Sopenharmony_ci		.gamma		= {
25662306a36Sopenharmony_ci			.len	= 256,
25762306a36Sopenharmony_ci			.bits	= 8,
25862306a36Sopenharmony_ci			.reg	= DISPC_GAMMA_TABLE0,
25962306a36Sopenharmony_ci			.has_index = true,
26062306a36Sopenharmony_ci		},
26162306a36Sopenharmony_ci		.reg_desc	= {
26262306a36Sopenharmony_ci			[DISPC_MGR_FLD_ENABLE]		= { DISPC_CONTROL,  0,  0 },
26362306a36Sopenharmony_ci			[DISPC_MGR_FLD_STNTFT]		= { DISPC_CONTROL,  3,  3 },
26462306a36Sopenharmony_ci			[DISPC_MGR_FLD_GO]		= { DISPC_CONTROL,  5,  5 },
26562306a36Sopenharmony_ci			[DISPC_MGR_FLD_TFTDATALINES]	= { DISPC_CONTROL,  9,  8 },
26662306a36Sopenharmony_ci			[DISPC_MGR_FLD_STALLMODE]	= { DISPC_CONTROL, 11, 11 },
26762306a36Sopenharmony_ci			[DISPC_MGR_FLD_TCKENABLE]	= { DISPC_CONFIG,  10, 10 },
26862306a36Sopenharmony_ci			[DISPC_MGR_FLD_TCKSELECTION]	= { DISPC_CONFIG,  11, 11 },
26962306a36Sopenharmony_ci			[DISPC_MGR_FLD_CPR]		= { DISPC_CONFIG,  15, 15 },
27062306a36Sopenharmony_ci			[DISPC_MGR_FLD_FIFOHANDCHECK]	= { DISPC_CONFIG,  16, 16 },
27162306a36Sopenharmony_ci		},
27262306a36Sopenharmony_ci	},
27362306a36Sopenharmony_ci	[OMAP_DSS_CHANNEL_DIGIT] = {
27462306a36Sopenharmony_ci		.name		= "DIGIT",
27562306a36Sopenharmony_ci		.vsync_irq	= DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN,
27662306a36Sopenharmony_ci		.framedone_irq	= DISPC_IRQ_FRAMEDONETV,
27762306a36Sopenharmony_ci		.sync_lost_irq	= DISPC_IRQ_SYNC_LOST_DIGIT,
27862306a36Sopenharmony_ci		.gamma		= {
27962306a36Sopenharmony_ci			.len	= 1024,
28062306a36Sopenharmony_ci			.bits	= 10,
28162306a36Sopenharmony_ci			.reg	= DISPC_GAMMA_TABLE2,
28262306a36Sopenharmony_ci			.has_index = false,
28362306a36Sopenharmony_ci		},
28462306a36Sopenharmony_ci		.reg_desc	= {
28562306a36Sopenharmony_ci			[DISPC_MGR_FLD_ENABLE]		= { DISPC_CONTROL,  1,  1 },
28662306a36Sopenharmony_ci			[DISPC_MGR_FLD_STNTFT]		= { },
28762306a36Sopenharmony_ci			[DISPC_MGR_FLD_GO]		= { DISPC_CONTROL,  6,  6 },
28862306a36Sopenharmony_ci			[DISPC_MGR_FLD_TFTDATALINES]	= { },
28962306a36Sopenharmony_ci			[DISPC_MGR_FLD_STALLMODE]	= { },
29062306a36Sopenharmony_ci			[DISPC_MGR_FLD_TCKENABLE]	= { DISPC_CONFIG,  12, 12 },
29162306a36Sopenharmony_ci			[DISPC_MGR_FLD_TCKSELECTION]	= { DISPC_CONFIG,  13, 13 },
29262306a36Sopenharmony_ci			[DISPC_MGR_FLD_CPR]		= { },
29362306a36Sopenharmony_ci			[DISPC_MGR_FLD_FIFOHANDCHECK]	= { DISPC_CONFIG,  16, 16 },
29462306a36Sopenharmony_ci		},
29562306a36Sopenharmony_ci	},
29662306a36Sopenharmony_ci	[OMAP_DSS_CHANNEL_LCD2] = {
29762306a36Sopenharmony_ci		.name		= "LCD2",
29862306a36Sopenharmony_ci		.vsync_irq	= DISPC_IRQ_VSYNC2,
29962306a36Sopenharmony_ci		.framedone_irq	= DISPC_IRQ_FRAMEDONE2,
30062306a36Sopenharmony_ci		.sync_lost_irq	= DISPC_IRQ_SYNC_LOST2,
30162306a36Sopenharmony_ci		.gamma		= {
30262306a36Sopenharmony_ci			.len	= 256,
30362306a36Sopenharmony_ci			.bits	= 8,
30462306a36Sopenharmony_ci			.reg	= DISPC_GAMMA_TABLE1,
30562306a36Sopenharmony_ci			.has_index = true,
30662306a36Sopenharmony_ci		},
30762306a36Sopenharmony_ci		.reg_desc	= {
30862306a36Sopenharmony_ci			[DISPC_MGR_FLD_ENABLE]		= { DISPC_CONTROL2,  0,  0 },
30962306a36Sopenharmony_ci			[DISPC_MGR_FLD_STNTFT]		= { DISPC_CONTROL2,  3,  3 },
31062306a36Sopenharmony_ci			[DISPC_MGR_FLD_GO]		= { DISPC_CONTROL2,  5,  5 },
31162306a36Sopenharmony_ci			[DISPC_MGR_FLD_TFTDATALINES]	= { DISPC_CONTROL2,  9,  8 },
31262306a36Sopenharmony_ci			[DISPC_MGR_FLD_STALLMODE]	= { DISPC_CONTROL2, 11, 11 },
31362306a36Sopenharmony_ci			[DISPC_MGR_FLD_TCKENABLE]	= { DISPC_CONFIG2,  10, 10 },
31462306a36Sopenharmony_ci			[DISPC_MGR_FLD_TCKSELECTION]	= { DISPC_CONFIG2,  11, 11 },
31562306a36Sopenharmony_ci			[DISPC_MGR_FLD_CPR]		= { DISPC_CONFIG2,  15, 15 },
31662306a36Sopenharmony_ci			[DISPC_MGR_FLD_FIFOHANDCHECK]	= { DISPC_CONFIG2,  16, 16 },
31762306a36Sopenharmony_ci		},
31862306a36Sopenharmony_ci	},
31962306a36Sopenharmony_ci	[OMAP_DSS_CHANNEL_LCD3] = {
32062306a36Sopenharmony_ci		.name		= "LCD3",
32162306a36Sopenharmony_ci		.vsync_irq	= DISPC_IRQ_VSYNC3,
32262306a36Sopenharmony_ci		.framedone_irq	= DISPC_IRQ_FRAMEDONE3,
32362306a36Sopenharmony_ci		.sync_lost_irq	= DISPC_IRQ_SYNC_LOST3,
32462306a36Sopenharmony_ci		.gamma		= {
32562306a36Sopenharmony_ci			.len	= 256,
32662306a36Sopenharmony_ci			.bits	= 8,
32762306a36Sopenharmony_ci			.reg	= DISPC_GAMMA_TABLE3,
32862306a36Sopenharmony_ci			.has_index = true,
32962306a36Sopenharmony_ci		},
33062306a36Sopenharmony_ci		.reg_desc	= {
33162306a36Sopenharmony_ci			[DISPC_MGR_FLD_ENABLE]		= { DISPC_CONTROL3,  0,  0 },
33262306a36Sopenharmony_ci			[DISPC_MGR_FLD_STNTFT]		= { DISPC_CONTROL3,  3,  3 },
33362306a36Sopenharmony_ci			[DISPC_MGR_FLD_GO]		= { DISPC_CONTROL3,  5,  5 },
33462306a36Sopenharmony_ci			[DISPC_MGR_FLD_TFTDATALINES]	= { DISPC_CONTROL3,  9,  8 },
33562306a36Sopenharmony_ci			[DISPC_MGR_FLD_STALLMODE]	= { DISPC_CONTROL3, 11, 11 },
33662306a36Sopenharmony_ci			[DISPC_MGR_FLD_TCKENABLE]	= { DISPC_CONFIG3,  10, 10 },
33762306a36Sopenharmony_ci			[DISPC_MGR_FLD_TCKSELECTION]	= { DISPC_CONFIG3,  11, 11 },
33862306a36Sopenharmony_ci			[DISPC_MGR_FLD_CPR]		= { DISPC_CONFIG3,  15, 15 },
33962306a36Sopenharmony_ci			[DISPC_MGR_FLD_FIFOHANDCHECK]	= { DISPC_CONFIG3,  16, 16 },
34062306a36Sopenharmony_ci		},
34162306a36Sopenharmony_ci	},
34262306a36Sopenharmony_ci};
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic unsigned long dispc_fclk_rate(struct dispc_device *dispc);
34562306a36Sopenharmony_cistatic unsigned long dispc_core_clk_rate(struct dispc_device *dispc);
34662306a36Sopenharmony_cistatic unsigned long dispc_mgr_lclk_rate(struct dispc_device *dispc,
34762306a36Sopenharmony_ci					 enum omap_channel channel);
34862306a36Sopenharmony_cistatic unsigned long dispc_mgr_pclk_rate(struct dispc_device *dispc,
34962306a36Sopenharmony_ci					 enum omap_channel channel);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic unsigned long dispc_plane_pclk_rate(struct dispc_device *dispc,
35262306a36Sopenharmony_ci					   enum omap_plane_id plane);
35362306a36Sopenharmony_cistatic unsigned long dispc_plane_lclk_rate(struct dispc_device *dispc,
35462306a36Sopenharmony_ci					   enum omap_plane_id plane);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic inline void dispc_write_reg(struct dispc_device *dispc, u16 idx, u32 val)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	__raw_writel(val, dispc->base + idx);
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic inline u32 dispc_read_reg(struct dispc_device *dispc, u16 idx)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	return __raw_readl(dispc->base + idx);
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic u32 mgr_fld_read(struct dispc_device *dispc, enum omap_channel channel,
36762306a36Sopenharmony_ci			enum mgr_reg_fields regfld)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	const struct dispc_reg_field *rfld = &mgr_desc[channel].reg_desc[regfld];
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	return REG_GET(dispc, rfld->reg, rfld->high, rfld->low);
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_cistatic void mgr_fld_write(struct dispc_device *dispc, enum omap_channel channel,
37562306a36Sopenharmony_ci			  enum mgr_reg_fields regfld, int val)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	const struct dispc_reg_field *rfld = &mgr_desc[channel].reg_desc[regfld];
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	REG_FLD_MOD(dispc, rfld->reg, val, rfld->high, rfld->low);
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ciint dispc_get_num_ovls(struct dispc_device *dispc)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	return dispc->feat->num_ovls;
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ciint dispc_get_num_mgrs(struct dispc_device *dispc)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	return dispc->feat->num_mgrs;
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic void dispc_get_reg_field(struct dispc_device *dispc,
39362306a36Sopenharmony_ci				enum dispc_feat_reg_field id,
39462306a36Sopenharmony_ci				u8 *start, u8 *end)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	BUG_ON(id >= dispc->feat->num_reg_fields);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	*start = dispc->feat->reg_fields[id].start;
39962306a36Sopenharmony_ci	*end = dispc->feat->reg_fields[id].end;
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic bool dispc_has_feature(struct dispc_device *dispc,
40362306a36Sopenharmony_ci			      enum dispc_feature_id id)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	unsigned int i;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	for (i = 0; i < dispc->feat->num_features; i++) {
40862306a36Sopenharmony_ci		if (dispc->feat->features[i] == id)
40962306a36Sopenharmony_ci			return true;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	return false;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci#define SR(dispc, reg) \
41662306a36Sopenharmony_ci	dispc->ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(dispc, DISPC_##reg)
41762306a36Sopenharmony_ci#define RR(dispc, reg) \
41862306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_##reg, dispc->ctx[DISPC_##reg / sizeof(u32)])
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic void dispc_save_context(struct dispc_device *dispc)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	int i, j;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	DSSDBG("dispc_save_context\n");
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	SR(dispc, IRQENABLE);
42762306a36Sopenharmony_ci	SR(dispc, CONTROL);
42862306a36Sopenharmony_ci	SR(dispc, CONFIG);
42962306a36Sopenharmony_ci	SR(dispc, LINE_NUMBER);
43062306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER) ||
43162306a36Sopenharmony_ci			dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER))
43262306a36Sopenharmony_ci		SR(dispc, GLOBAL_ALPHA);
43362306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) {
43462306a36Sopenharmony_ci		SR(dispc, CONTROL2);
43562306a36Sopenharmony_ci		SR(dispc, CONFIG2);
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) {
43862306a36Sopenharmony_ci		SR(dispc, CONTROL3);
43962306a36Sopenharmony_ci		SR(dispc, CONFIG3);
44062306a36Sopenharmony_ci	}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	for (i = 0; i < dispc_get_num_mgrs(dispc); i++) {
44362306a36Sopenharmony_ci		SR(dispc, DEFAULT_COLOR(i));
44462306a36Sopenharmony_ci		SR(dispc, TRANS_COLOR(i));
44562306a36Sopenharmony_ci		SR(dispc, SIZE_MGR(i));
44662306a36Sopenharmony_ci		if (i == OMAP_DSS_CHANNEL_DIGIT)
44762306a36Sopenharmony_ci			continue;
44862306a36Sopenharmony_ci		SR(dispc, TIMING_H(i));
44962306a36Sopenharmony_ci		SR(dispc, TIMING_V(i));
45062306a36Sopenharmony_ci		SR(dispc, POL_FREQ(i));
45162306a36Sopenharmony_ci		SR(dispc, DIVISORo(i));
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci		SR(dispc, DATA_CYCLE1(i));
45462306a36Sopenharmony_ci		SR(dispc, DATA_CYCLE2(i));
45562306a36Sopenharmony_ci		SR(dispc, DATA_CYCLE3(i));
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_CPR)) {
45862306a36Sopenharmony_ci			SR(dispc, CPR_COEF_R(i));
45962306a36Sopenharmony_ci			SR(dispc, CPR_COEF_G(i));
46062306a36Sopenharmony_ci			SR(dispc, CPR_COEF_B(i));
46162306a36Sopenharmony_ci		}
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	for (i = 0; i < dispc_get_num_ovls(dispc); i++) {
46562306a36Sopenharmony_ci		SR(dispc, OVL_BA0(i));
46662306a36Sopenharmony_ci		SR(dispc, OVL_BA1(i));
46762306a36Sopenharmony_ci		SR(dispc, OVL_POSITION(i));
46862306a36Sopenharmony_ci		SR(dispc, OVL_SIZE(i));
46962306a36Sopenharmony_ci		SR(dispc, OVL_ATTRIBUTES(i));
47062306a36Sopenharmony_ci		SR(dispc, OVL_FIFO_THRESHOLD(i));
47162306a36Sopenharmony_ci		SR(dispc, OVL_ROW_INC(i));
47262306a36Sopenharmony_ci		SR(dispc, OVL_PIXEL_INC(i));
47362306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_PRELOAD))
47462306a36Sopenharmony_ci			SR(dispc, OVL_PRELOAD(i));
47562306a36Sopenharmony_ci		if (i == OMAP_DSS_GFX) {
47662306a36Sopenharmony_ci			SR(dispc, OVL_WINDOW_SKIP(i));
47762306a36Sopenharmony_ci			SR(dispc, OVL_TABLE_BA(i));
47862306a36Sopenharmony_ci			continue;
47962306a36Sopenharmony_ci		}
48062306a36Sopenharmony_ci		SR(dispc, OVL_FIR(i));
48162306a36Sopenharmony_ci		SR(dispc, OVL_PICTURE_SIZE(i));
48262306a36Sopenharmony_ci		SR(dispc, OVL_ACCU0(i));
48362306a36Sopenharmony_ci		SR(dispc, OVL_ACCU1(i));
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci		for (j = 0; j < 8; j++)
48662306a36Sopenharmony_ci			SR(dispc, OVL_FIR_COEF_H(i, j));
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci		for (j = 0; j < 8; j++)
48962306a36Sopenharmony_ci			SR(dispc, OVL_FIR_COEF_HV(i, j));
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci		for (j = 0; j < 5; j++)
49262306a36Sopenharmony_ci			SR(dispc, OVL_CONV_COEF(i, j));
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_FIR_COEF_V)) {
49562306a36Sopenharmony_ci			for (j = 0; j < 8; j++)
49662306a36Sopenharmony_ci				SR(dispc, OVL_FIR_COEF_V(i, j));
49762306a36Sopenharmony_ci		}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) {
50062306a36Sopenharmony_ci			SR(dispc, OVL_BA0_UV(i));
50162306a36Sopenharmony_ci			SR(dispc, OVL_BA1_UV(i));
50262306a36Sopenharmony_ci			SR(dispc, OVL_FIR2(i));
50362306a36Sopenharmony_ci			SR(dispc, OVL_ACCU2_0(i));
50462306a36Sopenharmony_ci			SR(dispc, OVL_ACCU2_1(i));
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci			for (j = 0; j < 8; j++)
50762306a36Sopenharmony_ci				SR(dispc, OVL_FIR_COEF_H2(i, j));
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci			for (j = 0; j < 8; j++)
51062306a36Sopenharmony_ci				SR(dispc, OVL_FIR_COEF_HV2(i, j));
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci			for (j = 0; j < 8; j++)
51362306a36Sopenharmony_ci				SR(dispc, OVL_FIR_COEF_V2(i, j));
51462306a36Sopenharmony_ci		}
51562306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_ATTR2))
51662306a36Sopenharmony_ci			SR(dispc, OVL_ATTRIBUTES2(i));
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV))
52062306a36Sopenharmony_ci		SR(dispc, DIVISOR);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	dispc->ctx_valid = true;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	DSSDBG("context saved\n");
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistatic void dispc_restore_context(struct dispc_device *dispc)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	int i, j;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	DSSDBG("dispc_restore_context\n");
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	if (!dispc->ctx_valid)
53462306a36Sopenharmony_ci		return;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/*RR(dispc, IRQENABLE);*/
53762306a36Sopenharmony_ci	/*RR(dispc, CONTROL);*/
53862306a36Sopenharmony_ci	RR(dispc, CONFIG);
53962306a36Sopenharmony_ci	RR(dispc, LINE_NUMBER);
54062306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER) ||
54162306a36Sopenharmony_ci			dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER))
54262306a36Sopenharmony_ci		RR(dispc, GLOBAL_ALPHA);
54362306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_MGR_LCD2))
54462306a36Sopenharmony_ci		RR(dispc, CONFIG2);
54562306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_MGR_LCD3))
54662306a36Sopenharmony_ci		RR(dispc, CONFIG3);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	for (i = 0; i < dispc_get_num_mgrs(dispc); i++) {
54962306a36Sopenharmony_ci		RR(dispc, DEFAULT_COLOR(i));
55062306a36Sopenharmony_ci		RR(dispc, TRANS_COLOR(i));
55162306a36Sopenharmony_ci		RR(dispc, SIZE_MGR(i));
55262306a36Sopenharmony_ci		if (i == OMAP_DSS_CHANNEL_DIGIT)
55362306a36Sopenharmony_ci			continue;
55462306a36Sopenharmony_ci		RR(dispc, TIMING_H(i));
55562306a36Sopenharmony_ci		RR(dispc, TIMING_V(i));
55662306a36Sopenharmony_ci		RR(dispc, POL_FREQ(i));
55762306a36Sopenharmony_ci		RR(dispc, DIVISORo(i));
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci		RR(dispc, DATA_CYCLE1(i));
56062306a36Sopenharmony_ci		RR(dispc, DATA_CYCLE2(i));
56162306a36Sopenharmony_ci		RR(dispc, DATA_CYCLE3(i));
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_CPR)) {
56462306a36Sopenharmony_ci			RR(dispc, CPR_COEF_R(i));
56562306a36Sopenharmony_ci			RR(dispc, CPR_COEF_G(i));
56662306a36Sopenharmony_ci			RR(dispc, CPR_COEF_B(i));
56762306a36Sopenharmony_ci		}
56862306a36Sopenharmony_ci	}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	for (i = 0; i < dispc_get_num_ovls(dispc); i++) {
57162306a36Sopenharmony_ci		RR(dispc, OVL_BA0(i));
57262306a36Sopenharmony_ci		RR(dispc, OVL_BA1(i));
57362306a36Sopenharmony_ci		RR(dispc, OVL_POSITION(i));
57462306a36Sopenharmony_ci		RR(dispc, OVL_SIZE(i));
57562306a36Sopenharmony_ci		RR(dispc, OVL_ATTRIBUTES(i));
57662306a36Sopenharmony_ci		RR(dispc, OVL_FIFO_THRESHOLD(i));
57762306a36Sopenharmony_ci		RR(dispc, OVL_ROW_INC(i));
57862306a36Sopenharmony_ci		RR(dispc, OVL_PIXEL_INC(i));
57962306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_PRELOAD))
58062306a36Sopenharmony_ci			RR(dispc, OVL_PRELOAD(i));
58162306a36Sopenharmony_ci		if (i == OMAP_DSS_GFX) {
58262306a36Sopenharmony_ci			RR(dispc, OVL_WINDOW_SKIP(i));
58362306a36Sopenharmony_ci			RR(dispc, OVL_TABLE_BA(i));
58462306a36Sopenharmony_ci			continue;
58562306a36Sopenharmony_ci		}
58662306a36Sopenharmony_ci		RR(dispc, OVL_FIR(i));
58762306a36Sopenharmony_ci		RR(dispc, OVL_PICTURE_SIZE(i));
58862306a36Sopenharmony_ci		RR(dispc, OVL_ACCU0(i));
58962306a36Sopenharmony_ci		RR(dispc, OVL_ACCU1(i));
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci		for (j = 0; j < 8; j++)
59262306a36Sopenharmony_ci			RR(dispc, OVL_FIR_COEF_H(i, j));
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci		for (j = 0; j < 8; j++)
59562306a36Sopenharmony_ci			RR(dispc, OVL_FIR_COEF_HV(i, j));
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci		for (j = 0; j < 5; j++)
59862306a36Sopenharmony_ci			RR(dispc, OVL_CONV_COEF(i, j));
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_FIR_COEF_V)) {
60162306a36Sopenharmony_ci			for (j = 0; j < 8; j++)
60262306a36Sopenharmony_ci				RR(dispc, OVL_FIR_COEF_V(i, j));
60362306a36Sopenharmony_ci		}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) {
60662306a36Sopenharmony_ci			RR(dispc, OVL_BA0_UV(i));
60762306a36Sopenharmony_ci			RR(dispc, OVL_BA1_UV(i));
60862306a36Sopenharmony_ci			RR(dispc, OVL_FIR2(i));
60962306a36Sopenharmony_ci			RR(dispc, OVL_ACCU2_0(i));
61062306a36Sopenharmony_ci			RR(dispc, OVL_ACCU2_1(i));
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci			for (j = 0; j < 8; j++)
61362306a36Sopenharmony_ci				RR(dispc, OVL_FIR_COEF_H2(i, j));
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci			for (j = 0; j < 8; j++)
61662306a36Sopenharmony_ci				RR(dispc, OVL_FIR_COEF_HV2(i, j));
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci			for (j = 0; j < 8; j++)
61962306a36Sopenharmony_ci				RR(dispc, OVL_FIR_COEF_V2(i, j));
62062306a36Sopenharmony_ci		}
62162306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_ATTR2))
62262306a36Sopenharmony_ci			RR(dispc, OVL_ATTRIBUTES2(i));
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV))
62662306a36Sopenharmony_ci		RR(dispc, DIVISOR);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	/* enable last, because LCD & DIGIT enable are here */
62962306a36Sopenharmony_ci	RR(dispc, CONTROL);
63062306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_MGR_LCD2))
63162306a36Sopenharmony_ci		RR(dispc, CONTROL2);
63262306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_MGR_LCD3))
63362306a36Sopenharmony_ci		RR(dispc, CONTROL3);
63462306a36Sopenharmony_ci	/* clear spurious SYNC_LOST_DIGIT interrupts */
63562306a36Sopenharmony_ci	dispc_clear_irqstatus(dispc, DISPC_IRQ_SYNC_LOST_DIGIT);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	/*
63862306a36Sopenharmony_ci	 * enable last so IRQs won't trigger before
63962306a36Sopenharmony_ci	 * the context is fully restored
64062306a36Sopenharmony_ci	 */
64162306a36Sopenharmony_ci	RR(dispc, IRQENABLE);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	DSSDBG("context restored\n");
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci#undef SR
64762306a36Sopenharmony_ci#undef RR
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ciint dispc_runtime_get(struct dispc_device *dispc)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	int r;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	DSSDBG("dispc_runtime_get\n");
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	r = pm_runtime_get_sync(&dispc->pdev->dev);
65662306a36Sopenharmony_ci	if (WARN_ON(r < 0)) {
65762306a36Sopenharmony_ci		pm_runtime_put_noidle(&dispc->pdev->dev);
65862306a36Sopenharmony_ci		return r;
65962306a36Sopenharmony_ci	}
66062306a36Sopenharmony_ci	return 0;
66162306a36Sopenharmony_ci}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_civoid dispc_runtime_put(struct dispc_device *dispc)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	int r;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	DSSDBG("dispc_runtime_put\n");
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	r = pm_runtime_put_sync(&dispc->pdev->dev);
67062306a36Sopenharmony_ci	WARN_ON(r < 0 && r != -ENOSYS);
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ciu32 dispc_mgr_get_vsync_irq(struct dispc_device *dispc,
67462306a36Sopenharmony_ci				   enum omap_channel channel)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	return mgr_desc[channel].vsync_irq;
67762306a36Sopenharmony_ci}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ciu32 dispc_mgr_get_framedone_irq(struct dispc_device *dispc,
68062306a36Sopenharmony_ci				       enum omap_channel channel)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc->feat->no_framedone_tv)
68362306a36Sopenharmony_ci		return 0;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	return mgr_desc[channel].framedone_irq;
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ciu32 dispc_mgr_get_sync_lost_irq(struct dispc_device *dispc,
68962306a36Sopenharmony_ci				       enum omap_channel channel)
69062306a36Sopenharmony_ci{
69162306a36Sopenharmony_ci	return mgr_desc[channel].sync_lost_irq;
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ciu32 dispc_wb_get_framedone_irq(struct dispc_device *dispc)
69562306a36Sopenharmony_ci{
69662306a36Sopenharmony_ci	return DISPC_IRQ_FRAMEDONEWB;
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_civoid dispc_mgr_enable(struct dispc_device *dispc,
70062306a36Sopenharmony_ci			     enum omap_channel channel, bool enable)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	mgr_fld_write(dispc, channel, DISPC_MGR_FLD_ENABLE, enable);
70362306a36Sopenharmony_ci	/* flush posted write */
70462306a36Sopenharmony_ci	mgr_fld_read(dispc, channel, DISPC_MGR_FLD_ENABLE);
70562306a36Sopenharmony_ci}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_cistatic bool dispc_mgr_is_enabled(struct dispc_device *dispc,
70862306a36Sopenharmony_ci				 enum omap_channel channel)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	return !!mgr_fld_read(dispc, channel, DISPC_MGR_FLD_ENABLE);
71162306a36Sopenharmony_ci}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_cibool dispc_mgr_go_busy(struct dispc_device *dispc,
71462306a36Sopenharmony_ci			      enum omap_channel channel)
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	return mgr_fld_read(dispc, channel, DISPC_MGR_FLD_GO) == 1;
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_civoid dispc_mgr_go(struct dispc_device *dispc, enum omap_channel channel)
72062306a36Sopenharmony_ci{
72162306a36Sopenharmony_ci	WARN_ON(!dispc_mgr_is_enabled(dispc, channel));
72262306a36Sopenharmony_ci	WARN_ON(dispc_mgr_go_busy(dispc, channel));
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	DSSDBG("GO %s\n", mgr_desc[channel].name);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	mgr_fld_write(dispc, channel, DISPC_MGR_FLD_GO, 1);
72762306a36Sopenharmony_ci}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_cibool dispc_wb_go_busy(struct dispc_device *dispc)
73062306a36Sopenharmony_ci{
73162306a36Sopenharmony_ci	return REG_GET(dispc, DISPC_CONTROL2, 6, 6) == 1;
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_civoid dispc_wb_go(struct dispc_device *dispc)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	enum omap_plane_id plane = OMAP_DSS_WB;
73762306a36Sopenharmony_ci	bool enable, go;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	enable = REG_GET(dispc, DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	if (!enable)
74262306a36Sopenharmony_ci		return;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	go = REG_GET(dispc, DISPC_CONTROL2, 6, 6) == 1;
74562306a36Sopenharmony_ci	if (go) {
74662306a36Sopenharmony_ci		DSSERR("GO bit not down for WB\n");
74762306a36Sopenharmony_ci		return;
74862306a36Sopenharmony_ci	}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_CONTROL2, 1, 6, 6);
75162306a36Sopenharmony_ci}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_cistatic void dispc_ovl_write_firh_reg(struct dispc_device *dispc,
75462306a36Sopenharmony_ci				     enum omap_plane_id plane, int reg,
75562306a36Sopenharmony_ci				     u32 value)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_H(plane, reg), value);
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistatic void dispc_ovl_write_firhv_reg(struct dispc_device *dispc,
76162306a36Sopenharmony_ci				      enum omap_plane_id plane, int reg,
76262306a36Sopenharmony_ci				      u32 value)
76362306a36Sopenharmony_ci{
76462306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_HV(plane, reg), value);
76562306a36Sopenharmony_ci}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_cistatic void dispc_ovl_write_firv_reg(struct dispc_device *dispc,
76862306a36Sopenharmony_ci				     enum omap_plane_id plane, int reg,
76962306a36Sopenharmony_ci				     u32 value)
77062306a36Sopenharmony_ci{
77162306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_V(plane, reg), value);
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistatic void dispc_ovl_write_firh2_reg(struct dispc_device *dispc,
77562306a36Sopenharmony_ci				      enum omap_plane_id plane, int reg,
77662306a36Sopenharmony_ci				      u32 value)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	BUG_ON(plane == OMAP_DSS_GFX);
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_H2(plane, reg), value);
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_cistatic void dispc_ovl_write_firhv2_reg(struct dispc_device *dispc,
78462306a36Sopenharmony_ci				       enum omap_plane_id plane, int reg,
78562306a36Sopenharmony_ci				       u32 value)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	BUG_ON(plane == OMAP_DSS_GFX);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_HV2(plane, reg), value);
79062306a36Sopenharmony_ci}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_cistatic void dispc_ovl_write_firv2_reg(struct dispc_device *dispc,
79362306a36Sopenharmony_ci				      enum omap_plane_id plane, int reg,
79462306a36Sopenharmony_ci				      u32 value)
79562306a36Sopenharmony_ci{
79662306a36Sopenharmony_ci	BUG_ON(plane == OMAP_DSS_GFX);
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_V2(plane, reg), value);
79962306a36Sopenharmony_ci}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_cistatic void dispc_ovl_set_scale_coef(struct dispc_device *dispc,
80262306a36Sopenharmony_ci				     enum omap_plane_id plane, int fir_hinc,
80362306a36Sopenharmony_ci				     int fir_vinc, int five_taps,
80462306a36Sopenharmony_ci				     enum omap_color_component color_comp)
80562306a36Sopenharmony_ci{
80662306a36Sopenharmony_ci	const struct dispc_coef *h_coef, *v_coef;
80762306a36Sopenharmony_ci	int i;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	h_coef = dispc_ovl_get_scale_coef(fir_hinc, true);
81062306a36Sopenharmony_ci	v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	if (!h_coef || !v_coef) {
81362306a36Sopenharmony_ci		dev_err(&dispc->pdev->dev, "%s: failed to find scale coefs\n",
81462306a36Sopenharmony_ci			__func__);
81562306a36Sopenharmony_ci		return;
81662306a36Sopenharmony_ci	}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
81962306a36Sopenharmony_ci		u32 h, hv;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci		h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0)
82262306a36Sopenharmony_ci			| FLD_VAL(h_coef[i].hc1_vc0, 15, 8)
82362306a36Sopenharmony_ci			| FLD_VAL(h_coef[i].hc2_vc1, 23, 16)
82462306a36Sopenharmony_ci			| FLD_VAL(h_coef[i].hc3_vc2, 31, 24);
82562306a36Sopenharmony_ci		hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0)
82662306a36Sopenharmony_ci			| FLD_VAL(v_coef[i].hc1_vc0, 15, 8)
82762306a36Sopenharmony_ci			| FLD_VAL(v_coef[i].hc2_vc1, 23, 16)
82862306a36Sopenharmony_ci			| FLD_VAL(v_coef[i].hc3_vc2, 31, 24);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci		if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
83162306a36Sopenharmony_ci			dispc_ovl_write_firh_reg(dispc, plane, i, h);
83262306a36Sopenharmony_ci			dispc_ovl_write_firhv_reg(dispc, plane, i, hv);
83362306a36Sopenharmony_ci		} else {
83462306a36Sopenharmony_ci			dispc_ovl_write_firh2_reg(dispc, plane, i, h);
83562306a36Sopenharmony_ci			dispc_ovl_write_firhv2_reg(dispc, plane, i, hv);
83662306a36Sopenharmony_ci		}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	if (five_taps) {
84162306a36Sopenharmony_ci		for (i = 0; i < 8; i++) {
84262306a36Sopenharmony_ci			u32 v;
84362306a36Sopenharmony_ci			v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0)
84462306a36Sopenharmony_ci				| FLD_VAL(v_coef[i].hc4_vc22, 15, 8);
84562306a36Sopenharmony_ci			if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y)
84662306a36Sopenharmony_ci				dispc_ovl_write_firv_reg(dispc, plane, i, v);
84762306a36Sopenharmony_ci			else
84862306a36Sopenharmony_ci				dispc_ovl_write_firv2_reg(dispc, plane, i, v);
84962306a36Sopenharmony_ci		}
85062306a36Sopenharmony_ci	}
85162306a36Sopenharmony_ci}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_cistruct csc_coef_yuv2rgb {
85462306a36Sopenharmony_ci	int ry, rcb, rcr, gy, gcb, gcr, by, bcb, bcr;
85562306a36Sopenharmony_ci	bool full_range;
85662306a36Sopenharmony_ci};
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic void dispc_ovl_write_color_conv_coef(struct dispc_device *dispc,
85962306a36Sopenharmony_ci					    enum omap_plane_id plane,
86062306a36Sopenharmony_ci					    const struct csc_coef_yuv2rgb *ct)
86162306a36Sopenharmony_ci{
86262306a36Sopenharmony_ci#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry));
86562306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy,  ct->rcb));
86662306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr));
86762306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by));
86862306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb));
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci#undef CVAL
87362306a36Sopenharmony_ci}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci/* YUV -> RGB, ITU-R BT.601, full range */
87662306a36Sopenharmony_cistatic const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt601_full = {
87762306a36Sopenharmony_ci	256,   0,  358,		/* ry, rcb, rcr |1.000  0.000  1.402|*/
87862306a36Sopenharmony_ci	256, -88, -182,		/* gy, gcb, gcr |1.000 -0.344 -0.714|*/
87962306a36Sopenharmony_ci	256, 452,    0,		/* by, bcb, bcr |1.000  1.772  0.000|*/
88062306a36Sopenharmony_ci	true,			/* full range */
88162306a36Sopenharmony_ci};
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci/* YUV -> RGB, ITU-R BT.601, limited range */
88462306a36Sopenharmony_cistatic const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt601_lim = {
88562306a36Sopenharmony_ci	298,    0,  409,	/* ry, rcb, rcr |1.164  0.000  1.596|*/
88662306a36Sopenharmony_ci	298, -100, -208,	/* gy, gcb, gcr |1.164 -0.392 -0.813|*/
88762306a36Sopenharmony_ci	298,  516,    0,	/* by, bcb, bcr |1.164  2.017  0.000|*/
88862306a36Sopenharmony_ci	false,			/* limited range */
88962306a36Sopenharmony_ci};
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci/* YUV -> RGB, ITU-R BT.709, full range */
89262306a36Sopenharmony_cistatic const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt709_full = {
89362306a36Sopenharmony_ci	256,    0,  402,        /* ry, rcb, rcr |1.000  0.000  1.570|*/
89462306a36Sopenharmony_ci	256,  -48, -120,        /* gy, gcb, gcr |1.000 -0.187 -0.467|*/
89562306a36Sopenharmony_ci	256,  475,    0,        /* by, bcb, bcr |1.000  1.856  0.000|*/
89662306a36Sopenharmony_ci	true,                   /* full range */
89762306a36Sopenharmony_ci};
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci/* YUV -> RGB, ITU-R BT.709, limited range */
90062306a36Sopenharmony_cistatic const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt709_lim = {
90162306a36Sopenharmony_ci	298,    0,  459,	/* ry, rcb, rcr |1.164  0.000  1.793|*/
90262306a36Sopenharmony_ci	298,  -55, -136,	/* gy, gcb, gcr |1.164 -0.213 -0.533|*/
90362306a36Sopenharmony_ci	298,  541,    0,	/* by, bcb, bcr |1.164  2.112  0.000|*/
90462306a36Sopenharmony_ci	false,			/* limited range */
90562306a36Sopenharmony_ci};
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic void dispc_ovl_set_csc(struct dispc_device *dispc,
90862306a36Sopenharmony_ci			      enum omap_plane_id plane,
90962306a36Sopenharmony_ci			      enum drm_color_encoding color_encoding,
91062306a36Sopenharmony_ci			      enum drm_color_range color_range)
91162306a36Sopenharmony_ci{
91262306a36Sopenharmony_ci	const struct csc_coef_yuv2rgb *csc;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	switch (color_encoding) {
91562306a36Sopenharmony_ci	default:
91662306a36Sopenharmony_ci	case DRM_COLOR_YCBCR_BT601:
91762306a36Sopenharmony_ci		if (color_range == DRM_COLOR_YCBCR_FULL_RANGE)
91862306a36Sopenharmony_ci			csc = &coefs_yuv2rgb_bt601_full;
91962306a36Sopenharmony_ci		else
92062306a36Sopenharmony_ci			csc = &coefs_yuv2rgb_bt601_lim;
92162306a36Sopenharmony_ci		break;
92262306a36Sopenharmony_ci	case DRM_COLOR_YCBCR_BT709:
92362306a36Sopenharmony_ci		if (color_range == DRM_COLOR_YCBCR_FULL_RANGE)
92462306a36Sopenharmony_ci			csc = &coefs_yuv2rgb_bt709_full;
92562306a36Sopenharmony_ci		else
92662306a36Sopenharmony_ci			csc = &coefs_yuv2rgb_bt709_lim;
92762306a36Sopenharmony_ci		break;
92862306a36Sopenharmony_ci	}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	dispc_ovl_write_color_conv_coef(dispc, plane, csc);
93162306a36Sopenharmony_ci}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_cistatic void dispc_ovl_set_ba0(struct dispc_device *dispc,
93462306a36Sopenharmony_ci			      enum omap_plane_id plane, u32 paddr)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_BA0(plane), paddr);
93762306a36Sopenharmony_ci}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_cistatic void dispc_ovl_set_ba1(struct dispc_device *dispc,
94062306a36Sopenharmony_ci			      enum omap_plane_id plane, u32 paddr)
94162306a36Sopenharmony_ci{
94262306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_BA1(plane), paddr);
94362306a36Sopenharmony_ci}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_cistatic void dispc_ovl_set_ba0_uv(struct dispc_device *dispc,
94662306a36Sopenharmony_ci				 enum omap_plane_id plane, u32 paddr)
94762306a36Sopenharmony_ci{
94862306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_BA0_UV(plane), paddr);
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_cistatic void dispc_ovl_set_ba1_uv(struct dispc_device *dispc,
95262306a36Sopenharmony_ci				 enum omap_plane_id plane, u32 paddr)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_BA1_UV(plane), paddr);
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_cistatic void dispc_ovl_set_pos(struct dispc_device *dispc,
95862306a36Sopenharmony_ci			      enum omap_plane_id plane,
95962306a36Sopenharmony_ci			      enum omap_overlay_caps caps, int x, int y)
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	u32 val;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	if ((caps & OMAP_DSS_OVL_CAP_POS) == 0)
96462306a36Sopenharmony_ci		return;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_POSITION(plane), val);
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_cistatic void dispc_ovl_set_input_size(struct dispc_device *dispc,
97262306a36Sopenharmony_ci				     enum omap_plane_id plane, int width,
97362306a36Sopenharmony_ci				     int height)
97462306a36Sopenharmony_ci{
97562306a36Sopenharmony_ci	u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB)
97862306a36Sopenharmony_ci		dispc_write_reg(dispc, DISPC_OVL_SIZE(plane), val);
97962306a36Sopenharmony_ci	else
98062306a36Sopenharmony_ci		dispc_write_reg(dispc, DISPC_OVL_PICTURE_SIZE(plane), val);
98162306a36Sopenharmony_ci}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_cistatic void dispc_ovl_set_output_size(struct dispc_device *dispc,
98462306a36Sopenharmony_ci				      enum omap_plane_id plane, int width,
98562306a36Sopenharmony_ci				      int height)
98662306a36Sopenharmony_ci{
98762306a36Sopenharmony_ci	u32 val;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	BUG_ON(plane == OMAP_DSS_GFX);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	if (plane == OMAP_DSS_WB)
99462306a36Sopenharmony_ci		dispc_write_reg(dispc, DISPC_OVL_PICTURE_SIZE(plane), val);
99562306a36Sopenharmony_ci	else
99662306a36Sopenharmony_ci		dispc_write_reg(dispc, DISPC_OVL_SIZE(plane), val);
99762306a36Sopenharmony_ci}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_cistatic void dispc_ovl_set_zorder(struct dispc_device *dispc,
100062306a36Sopenharmony_ci				 enum omap_plane_id plane,
100162306a36Sopenharmony_ci				 enum omap_overlay_caps caps, u8 zorder)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci	if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
100462306a36Sopenharmony_ci		return;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26);
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cistatic void dispc_ovl_enable_zorder_planes(struct dispc_device *dispc)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	int i;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	if (!dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER))
101462306a36Sopenharmony_ci		return;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	for (i = 0; i < dispc_get_num_ovls(dispc); i++)
101762306a36Sopenharmony_ci		REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(i), 1, 25, 25);
101862306a36Sopenharmony_ci}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_cistatic void dispc_ovl_set_pre_mult_alpha(struct dispc_device *dispc,
102162306a36Sopenharmony_ci					 enum omap_plane_id plane,
102262306a36Sopenharmony_ci					 enum omap_overlay_caps caps,
102362306a36Sopenharmony_ci					 bool enable)
102462306a36Sopenharmony_ci{
102562306a36Sopenharmony_ci	if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
102662306a36Sopenharmony_ci		return;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_cistatic void dispc_ovl_setup_global_alpha(struct dispc_device *dispc,
103262306a36Sopenharmony_ci					 enum omap_plane_id plane,
103362306a36Sopenharmony_ci					 enum omap_overlay_caps caps,
103462306a36Sopenharmony_ci					 u8 global_alpha)
103562306a36Sopenharmony_ci{
103662306a36Sopenharmony_ci	static const unsigned int shifts[] = { 0, 8, 16, 24, };
103762306a36Sopenharmony_ci	int shift;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
104062306a36Sopenharmony_ci		return;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	shift = shifts[plane];
104362306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift);
104462306a36Sopenharmony_ci}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_cistatic void dispc_ovl_set_pix_inc(struct dispc_device *dispc,
104762306a36Sopenharmony_ci				  enum omap_plane_id plane, s32 inc)
104862306a36Sopenharmony_ci{
104962306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_PIXEL_INC(plane), inc);
105062306a36Sopenharmony_ci}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_cistatic void dispc_ovl_set_row_inc(struct dispc_device *dispc,
105362306a36Sopenharmony_ci				  enum omap_plane_id plane, s32 inc)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_ROW_INC(plane), inc);
105662306a36Sopenharmony_ci}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_cistatic void dispc_ovl_set_color_mode(struct dispc_device *dispc,
105962306a36Sopenharmony_ci				     enum omap_plane_id plane, u32 fourcc)
106062306a36Sopenharmony_ci{
106162306a36Sopenharmony_ci	u32 m = 0;
106262306a36Sopenharmony_ci	if (plane != OMAP_DSS_GFX) {
106362306a36Sopenharmony_ci		switch (fourcc) {
106462306a36Sopenharmony_ci		case DRM_FORMAT_NV12:
106562306a36Sopenharmony_ci			m = 0x0; break;
106662306a36Sopenharmony_ci		case DRM_FORMAT_XRGB4444:
106762306a36Sopenharmony_ci			m = 0x1; break;
106862306a36Sopenharmony_ci		case DRM_FORMAT_RGBA4444:
106962306a36Sopenharmony_ci			m = 0x2; break;
107062306a36Sopenharmony_ci		case DRM_FORMAT_RGBX4444:
107162306a36Sopenharmony_ci			m = 0x4; break;
107262306a36Sopenharmony_ci		case DRM_FORMAT_ARGB4444:
107362306a36Sopenharmony_ci			m = 0x5; break;
107462306a36Sopenharmony_ci		case DRM_FORMAT_RGB565:
107562306a36Sopenharmony_ci			m = 0x6; break;
107662306a36Sopenharmony_ci		case DRM_FORMAT_ARGB1555:
107762306a36Sopenharmony_ci			m = 0x7; break;
107862306a36Sopenharmony_ci		case DRM_FORMAT_XRGB8888:
107962306a36Sopenharmony_ci			m = 0x8; break;
108062306a36Sopenharmony_ci		case DRM_FORMAT_RGB888:
108162306a36Sopenharmony_ci			m = 0x9; break;
108262306a36Sopenharmony_ci		case DRM_FORMAT_YUYV:
108362306a36Sopenharmony_ci			m = 0xa; break;
108462306a36Sopenharmony_ci		case DRM_FORMAT_UYVY:
108562306a36Sopenharmony_ci			m = 0xb; break;
108662306a36Sopenharmony_ci		case DRM_FORMAT_ARGB8888:
108762306a36Sopenharmony_ci			m = 0xc; break;
108862306a36Sopenharmony_ci		case DRM_FORMAT_RGBA8888:
108962306a36Sopenharmony_ci			m = 0xd; break;
109062306a36Sopenharmony_ci		case DRM_FORMAT_RGBX8888:
109162306a36Sopenharmony_ci			m = 0xe; break;
109262306a36Sopenharmony_ci		case DRM_FORMAT_XRGB1555:
109362306a36Sopenharmony_ci			m = 0xf; break;
109462306a36Sopenharmony_ci		default:
109562306a36Sopenharmony_ci			BUG(); return;
109662306a36Sopenharmony_ci		}
109762306a36Sopenharmony_ci	} else {
109862306a36Sopenharmony_ci		switch (fourcc) {
109962306a36Sopenharmony_ci		case DRM_FORMAT_RGBX4444:
110062306a36Sopenharmony_ci			m = 0x4; break;
110162306a36Sopenharmony_ci		case DRM_FORMAT_ARGB4444:
110262306a36Sopenharmony_ci			m = 0x5; break;
110362306a36Sopenharmony_ci		case DRM_FORMAT_RGB565:
110462306a36Sopenharmony_ci			m = 0x6; break;
110562306a36Sopenharmony_ci		case DRM_FORMAT_ARGB1555:
110662306a36Sopenharmony_ci			m = 0x7; break;
110762306a36Sopenharmony_ci		case DRM_FORMAT_XRGB8888:
110862306a36Sopenharmony_ci			m = 0x8; break;
110962306a36Sopenharmony_ci		case DRM_FORMAT_RGB888:
111062306a36Sopenharmony_ci			m = 0x9; break;
111162306a36Sopenharmony_ci		case DRM_FORMAT_XRGB4444:
111262306a36Sopenharmony_ci			m = 0xa; break;
111362306a36Sopenharmony_ci		case DRM_FORMAT_RGBA4444:
111462306a36Sopenharmony_ci			m = 0xb; break;
111562306a36Sopenharmony_ci		case DRM_FORMAT_ARGB8888:
111662306a36Sopenharmony_ci			m = 0xc; break;
111762306a36Sopenharmony_ci		case DRM_FORMAT_RGBA8888:
111862306a36Sopenharmony_ci			m = 0xd; break;
111962306a36Sopenharmony_ci		case DRM_FORMAT_RGBX8888:
112062306a36Sopenharmony_ci			m = 0xe; break;
112162306a36Sopenharmony_ci		case DRM_FORMAT_XRGB1555:
112262306a36Sopenharmony_ci			m = 0xf; break;
112362306a36Sopenharmony_ci		default:
112462306a36Sopenharmony_ci			BUG(); return;
112562306a36Sopenharmony_ci		}
112662306a36Sopenharmony_ci	}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
112962306a36Sopenharmony_ci}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_cistatic void dispc_ovl_configure_burst_type(struct dispc_device *dispc,
113262306a36Sopenharmony_ci					   enum omap_plane_id plane,
113362306a36Sopenharmony_ci					   enum omap_dss_rotation_type rotation)
113462306a36Sopenharmony_ci{
113562306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_BURST_2D) == 0)
113662306a36Sopenharmony_ci		return;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	if (rotation == OMAP_DSS_ROT_TILER)
113962306a36Sopenharmony_ci		REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29);
114062306a36Sopenharmony_ci	else
114162306a36Sopenharmony_ci		REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29);
114262306a36Sopenharmony_ci}
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_cistatic void dispc_ovl_set_channel_out(struct dispc_device *dispc,
114562306a36Sopenharmony_ci				      enum omap_plane_id plane,
114662306a36Sopenharmony_ci				      enum omap_channel channel)
114762306a36Sopenharmony_ci{
114862306a36Sopenharmony_ci	int shift;
114962306a36Sopenharmony_ci	u32 val;
115062306a36Sopenharmony_ci	int chan = 0, chan2 = 0;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	switch (plane) {
115362306a36Sopenharmony_ci	case OMAP_DSS_GFX:
115462306a36Sopenharmony_ci		shift = 8;
115562306a36Sopenharmony_ci		break;
115662306a36Sopenharmony_ci	case OMAP_DSS_VIDEO1:
115762306a36Sopenharmony_ci	case OMAP_DSS_VIDEO2:
115862306a36Sopenharmony_ci	case OMAP_DSS_VIDEO3:
115962306a36Sopenharmony_ci		shift = 16;
116062306a36Sopenharmony_ci		break;
116162306a36Sopenharmony_ci	default:
116262306a36Sopenharmony_ci		BUG();
116362306a36Sopenharmony_ci		return;
116462306a36Sopenharmony_ci	}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	val = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane));
116762306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) {
116862306a36Sopenharmony_ci		switch (channel) {
116962306a36Sopenharmony_ci		case OMAP_DSS_CHANNEL_LCD:
117062306a36Sopenharmony_ci			chan = 0;
117162306a36Sopenharmony_ci			chan2 = 0;
117262306a36Sopenharmony_ci			break;
117362306a36Sopenharmony_ci		case OMAP_DSS_CHANNEL_DIGIT:
117462306a36Sopenharmony_ci			chan = 1;
117562306a36Sopenharmony_ci			chan2 = 0;
117662306a36Sopenharmony_ci			break;
117762306a36Sopenharmony_ci		case OMAP_DSS_CHANNEL_LCD2:
117862306a36Sopenharmony_ci			chan = 0;
117962306a36Sopenharmony_ci			chan2 = 1;
118062306a36Sopenharmony_ci			break;
118162306a36Sopenharmony_ci		case OMAP_DSS_CHANNEL_LCD3:
118262306a36Sopenharmony_ci			if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) {
118362306a36Sopenharmony_ci				chan = 0;
118462306a36Sopenharmony_ci				chan2 = 2;
118562306a36Sopenharmony_ci			} else {
118662306a36Sopenharmony_ci				BUG();
118762306a36Sopenharmony_ci				return;
118862306a36Sopenharmony_ci			}
118962306a36Sopenharmony_ci			break;
119062306a36Sopenharmony_ci		case OMAP_DSS_CHANNEL_WB:
119162306a36Sopenharmony_ci			chan = 0;
119262306a36Sopenharmony_ci			chan2 = 3;
119362306a36Sopenharmony_ci			break;
119462306a36Sopenharmony_ci		default:
119562306a36Sopenharmony_ci			BUG();
119662306a36Sopenharmony_ci			return;
119762306a36Sopenharmony_ci		}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci		val = FLD_MOD(val, chan, shift, shift);
120062306a36Sopenharmony_ci		val = FLD_MOD(val, chan2, 31, 30);
120162306a36Sopenharmony_ci	} else {
120262306a36Sopenharmony_ci		val = FLD_MOD(val, channel, shift, shift);
120362306a36Sopenharmony_ci	}
120462306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), val);
120562306a36Sopenharmony_ci}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_cistatic enum omap_channel dispc_ovl_get_channel_out(struct dispc_device *dispc,
120862306a36Sopenharmony_ci						   enum omap_plane_id plane)
120962306a36Sopenharmony_ci{
121062306a36Sopenharmony_ci	int shift;
121162306a36Sopenharmony_ci	u32 val;
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	switch (plane) {
121462306a36Sopenharmony_ci	case OMAP_DSS_GFX:
121562306a36Sopenharmony_ci		shift = 8;
121662306a36Sopenharmony_ci		break;
121762306a36Sopenharmony_ci	case OMAP_DSS_VIDEO1:
121862306a36Sopenharmony_ci	case OMAP_DSS_VIDEO2:
121962306a36Sopenharmony_ci	case OMAP_DSS_VIDEO3:
122062306a36Sopenharmony_ci		shift = 16;
122162306a36Sopenharmony_ci		break;
122262306a36Sopenharmony_ci	default:
122362306a36Sopenharmony_ci		BUG();
122462306a36Sopenharmony_ci		return 0;
122562306a36Sopenharmony_ci	}
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	val = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane));
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	if (FLD_GET(val, shift, shift) == 1)
123062306a36Sopenharmony_ci		return OMAP_DSS_CHANNEL_DIGIT;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	if (!dispc_has_feature(dispc, FEAT_MGR_LCD2))
123362306a36Sopenharmony_ci		return OMAP_DSS_CHANNEL_LCD;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	switch (FLD_GET(val, 31, 30)) {
123662306a36Sopenharmony_ci	case 0:
123762306a36Sopenharmony_ci	default:
123862306a36Sopenharmony_ci		return OMAP_DSS_CHANNEL_LCD;
123962306a36Sopenharmony_ci	case 1:
124062306a36Sopenharmony_ci		return OMAP_DSS_CHANNEL_LCD2;
124162306a36Sopenharmony_ci	case 2:
124262306a36Sopenharmony_ci		return OMAP_DSS_CHANNEL_LCD3;
124362306a36Sopenharmony_ci	case 3:
124462306a36Sopenharmony_ci		return OMAP_DSS_CHANNEL_WB;
124562306a36Sopenharmony_ci	}
124662306a36Sopenharmony_ci}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_cistatic void dispc_ovl_set_burst_size(struct dispc_device *dispc,
124962306a36Sopenharmony_ci				     enum omap_plane_id plane,
125062306a36Sopenharmony_ci				     enum omap_burst_size burst_size)
125162306a36Sopenharmony_ci{
125262306a36Sopenharmony_ci	static const unsigned int shifts[] = { 6, 14, 14, 14, 14, };
125362306a36Sopenharmony_ci	int shift;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	shift = shifts[plane];
125662306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), burst_size,
125762306a36Sopenharmony_ci		    shift + 1, shift);
125862306a36Sopenharmony_ci}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_cistatic void dispc_configure_burst_sizes(struct dispc_device *dispc)
126162306a36Sopenharmony_ci{
126262306a36Sopenharmony_ci	int i;
126362306a36Sopenharmony_ci	const int burst_size = BURST_SIZE_X8;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	/* Configure burst size always to maximum size */
126662306a36Sopenharmony_ci	for (i = 0; i < dispc_get_num_ovls(dispc); ++i)
126762306a36Sopenharmony_ci		dispc_ovl_set_burst_size(dispc, i, burst_size);
126862306a36Sopenharmony_ci	if (dispc->feat->has_writeback)
126962306a36Sopenharmony_ci		dispc_ovl_set_burst_size(dispc, OMAP_DSS_WB, burst_size);
127062306a36Sopenharmony_ci}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_cistatic u32 dispc_ovl_get_burst_size(struct dispc_device *dispc,
127362306a36Sopenharmony_ci				    enum omap_plane_id plane)
127462306a36Sopenharmony_ci{
127562306a36Sopenharmony_ci	/* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
127662306a36Sopenharmony_ci	return dispc->feat->burst_size_unit * 8;
127762306a36Sopenharmony_ci}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_cibool dispc_ovl_color_mode_supported(struct dispc_device *dispc,
128062306a36Sopenharmony_ci				    enum omap_plane_id plane, u32 fourcc)
128162306a36Sopenharmony_ci{
128262306a36Sopenharmony_ci	const u32 *modes;
128362306a36Sopenharmony_ci	unsigned int i;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	modes = dispc->feat->supported_color_modes[plane];
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	for (i = 0; modes[i]; ++i) {
128862306a36Sopenharmony_ci		if (modes[i] == fourcc)
128962306a36Sopenharmony_ci			return true;
129062306a36Sopenharmony_ci	}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	return false;
129362306a36Sopenharmony_ci}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ciconst u32 *dispc_ovl_get_color_modes(struct dispc_device *dispc,
129662306a36Sopenharmony_ci					    enum omap_plane_id plane)
129762306a36Sopenharmony_ci{
129862306a36Sopenharmony_ci	return dispc->feat->supported_color_modes[plane];
129962306a36Sopenharmony_ci}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_cistatic void dispc_mgr_enable_cpr(struct dispc_device *dispc,
130262306a36Sopenharmony_ci				 enum omap_channel channel, bool enable)
130362306a36Sopenharmony_ci{
130462306a36Sopenharmony_ci	if (channel == OMAP_DSS_CHANNEL_DIGIT)
130562306a36Sopenharmony_ci		return;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	mgr_fld_write(dispc, channel, DISPC_MGR_FLD_CPR, enable);
130862306a36Sopenharmony_ci}
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_cistatic void dispc_mgr_set_cpr_coef(struct dispc_device *dispc,
131162306a36Sopenharmony_ci				   enum omap_channel channel,
131262306a36Sopenharmony_ci				   const struct omap_dss_cpr_coefs *coefs)
131362306a36Sopenharmony_ci{
131462306a36Sopenharmony_ci	u32 coef_r, coef_g, coef_b;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	if (!dss_mgr_is_lcd(channel))
131762306a36Sopenharmony_ci		return;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) |
132062306a36Sopenharmony_ci		FLD_VAL(coefs->rb, 9, 0);
132162306a36Sopenharmony_ci	coef_g = FLD_VAL(coefs->gr, 31, 22) | FLD_VAL(coefs->gg, 20, 11) |
132262306a36Sopenharmony_ci		FLD_VAL(coefs->gb, 9, 0);
132362306a36Sopenharmony_ci	coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) |
132462306a36Sopenharmony_ci		FLD_VAL(coefs->bb, 9, 0);
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_CPR_COEF_R(channel), coef_r);
132762306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_CPR_COEF_G(channel), coef_g);
132862306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_CPR_COEF_B(channel), coef_b);
132962306a36Sopenharmony_ci}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_cistatic void dispc_ovl_set_vid_color_conv(struct dispc_device *dispc,
133262306a36Sopenharmony_ci					 enum omap_plane_id plane, bool enable)
133362306a36Sopenharmony_ci{
133462306a36Sopenharmony_ci	u32 val;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	BUG_ON(plane == OMAP_DSS_GFX);
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	val = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane));
133962306a36Sopenharmony_ci	val = FLD_MOD(val, enable, 9, 9);
134062306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), val);
134162306a36Sopenharmony_ci}
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_cistatic void dispc_ovl_enable_replication(struct dispc_device *dispc,
134462306a36Sopenharmony_ci					 enum omap_plane_id plane,
134562306a36Sopenharmony_ci					 enum omap_overlay_caps caps,
134662306a36Sopenharmony_ci					 bool enable)
134762306a36Sopenharmony_ci{
134862306a36Sopenharmony_ci	static const unsigned int shifts[] = { 5, 10, 10, 10 };
134962306a36Sopenharmony_ci	int shift;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0)
135262306a36Sopenharmony_ci		return;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	shift = shifts[plane];
135562306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift);
135662306a36Sopenharmony_ci}
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_cistatic void dispc_mgr_set_size(struct dispc_device *dispc,
135962306a36Sopenharmony_ci			       enum omap_channel channel, u16 width, u16 height)
136062306a36Sopenharmony_ci{
136162306a36Sopenharmony_ci	u32 val;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	val = FLD_VAL(height - 1, dispc->feat->mgr_height_start, 16) |
136462306a36Sopenharmony_ci		FLD_VAL(width - 1, dispc->feat->mgr_width_start, 0);
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_SIZE_MGR(channel), val);
136762306a36Sopenharmony_ci}
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_cistatic void dispc_init_fifos(struct dispc_device *dispc)
137062306a36Sopenharmony_ci{
137162306a36Sopenharmony_ci	u32 size;
137262306a36Sopenharmony_ci	int fifo;
137362306a36Sopenharmony_ci	u8 start, end;
137462306a36Sopenharmony_ci	u32 unit;
137562306a36Sopenharmony_ci	int i;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	unit = dispc->feat->buffer_size_unit;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	dispc_get_reg_field(dispc, FEAT_REG_FIFOSIZE, &start, &end);
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	for (fifo = 0; fifo < dispc->feat->num_fifos; ++fifo) {
138262306a36Sopenharmony_ci		size = REG_GET(dispc, DISPC_OVL_FIFO_SIZE_STATUS(fifo),
138362306a36Sopenharmony_ci			       start, end);
138462306a36Sopenharmony_ci		size *= unit;
138562306a36Sopenharmony_ci		dispc->fifo_size[fifo] = size;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci		/*
138862306a36Sopenharmony_ci		 * By default fifos are mapped directly to overlays, fifo 0 to
138962306a36Sopenharmony_ci		 * ovl 0, fifo 1 to ovl 1, etc.
139062306a36Sopenharmony_ci		 */
139162306a36Sopenharmony_ci		dispc->fifo_assignment[fifo] = fifo;
139262306a36Sopenharmony_ci	}
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	/*
139562306a36Sopenharmony_ci	 * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo
139662306a36Sopenharmony_ci	 * causes problems with certain use cases, like using the tiler in 2D
139762306a36Sopenharmony_ci	 * mode. The below hack swaps the fifos of GFX and WB planes, thus
139862306a36Sopenharmony_ci	 * giving GFX plane a larger fifo. WB but should work fine with a
139962306a36Sopenharmony_ci	 * smaller fifo.
140062306a36Sopenharmony_ci	 */
140162306a36Sopenharmony_ci	if (dispc->feat->gfx_fifo_workaround) {
140262306a36Sopenharmony_ci		u32 v;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci		v = dispc_read_reg(dispc, DISPC_GLOBAL_BUFFER);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci		v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */
140762306a36Sopenharmony_ci		v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */
140862306a36Sopenharmony_ci		v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */
140962306a36Sopenharmony_ci		v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci		dispc_write_reg(dispc, DISPC_GLOBAL_BUFFER, v);
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci		dispc->fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB;
141462306a36Sopenharmony_ci		dispc->fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX;
141562306a36Sopenharmony_ci	}
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	/*
141862306a36Sopenharmony_ci	 * Setup default fifo thresholds.
141962306a36Sopenharmony_ci	 */
142062306a36Sopenharmony_ci	for (i = 0; i < dispc_get_num_ovls(dispc); ++i) {
142162306a36Sopenharmony_ci		u32 low, high;
142262306a36Sopenharmony_ci		const bool use_fifomerge = false;
142362306a36Sopenharmony_ci		const bool manual_update = false;
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci		dispc_ovl_compute_fifo_thresholds(dispc, i, &low, &high,
142662306a36Sopenharmony_ci						  use_fifomerge, manual_update);
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci		dispc_ovl_set_fifo_threshold(dispc, i, low, high);
142962306a36Sopenharmony_ci	}
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	if (dispc->feat->has_writeback) {
143262306a36Sopenharmony_ci		u32 low, high;
143362306a36Sopenharmony_ci		const bool use_fifomerge = false;
143462306a36Sopenharmony_ci		const bool manual_update = false;
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci		dispc_ovl_compute_fifo_thresholds(dispc, OMAP_DSS_WB,
143762306a36Sopenharmony_ci						  &low, &high, use_fifomerge,
143862306a36Sopenharmony_ci						  manual_update);
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci		dispc_ovl_set_fifo_threshold(dispc, OMAP_DSS_WB, low, high);
144162306a36Sopenharmony_ci	}
144262306a36Sopenharmony_ci}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_cistatic u32 dispc_ovl_get_fifo_size(struct dispc_device *dispc,
144562306a36Sopenharmony_ci				   enum omap_plane_id plane)
144662306a36Sopenharmony_ci{
144762306a36Sopenharmony_ci	int fifo;
144862306a36Sopenharmony_ci	u32 size = 0;
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	for (fifo = 0; fifo < dispc->feat->num_fifos; ++fifo) {
145162306a36Sopenharmony_ci		if (dispc->fifo_assignment[fifo] == plane)
145262306a36Sopenharmony_ci			size += dispc->fifo_size[fifo];
145362306a36Sopenharmony_ci	}
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	return size;
145662306a36Sopenharmony_ci}
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_civoid dispc_ovl_set_fifo_threshold(struct dispc_device *dispc,
145962306a36Sopenharmony_ci				  enum omap_plane_id plane,
146062306a36Sopenharmony_ci				  u32 low, u32 high)
146162306a36Sopenharmony_ci{
146262306a36Sopenharmony_ci	u8 hi_start, hi_end, lo_start, lo_end;
146362306a36Sopenharmony_ci	u32 unit;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	unit = dispc->feat->buffer_size_unit;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	WARN_ON(low % unit != 0);
146862306a36Sopenharmony_ci	WARN_ON(high % unit != 0);
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	low /= unit;
147162306a36Sopenharmony_ci	high /= unit;
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	dispc_get_reg_field(dispc, FEAT_REG_FIFOHIGHTHRESHOLD,
147462306a36Sopenharmony_ci			    &hi_start, &hi_end);
147562306a36Sopenharmony_ci	dispc_get_reg_field(dispc, FEAT_REG_FIFOLOWTHRESHOLD,
147662306a36Sopenharmony_ci			    &lo_start, &lo_end);
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n",
147962306a36Sopenharmony_ci			plane,
148062306a36Sopenharmony_ci			REG_GET(dispc, DISPC_OVL_FIFO_THRESHOLD(plane),
148162306a36Sopenharmony_ci				lo_start, lo_end) * unit,
148262306a36Sopenharmony_ci			REG_GET(dispc, DISPC_OVL_FIFO_THRESHOLD(plane),
148362306a36Sopenharmony_ci				hi_start, hi_end) * unit,
148462306a36Sopenharmony_ci			low * unit, high * unit);
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_FIFO_THRESHOLD(plane),
148762306a36Sopenharmony_ci			FLD_VAL(high, hi_start, hi_end) |
148862306a36Sopenharmony_ci			FLD_VAL(low, lo_start, lo_end));
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	/*
149162306a36Sopenharmony_ci	 * configure the preload to the pipeline's high threhold, if HT it's too
149262306a36Sopenharmony_ci	 * large for the preload field, set the threshold to the maximum value
149362306a36Sopenharmony_ci	 * that can be held by the preload register
149462306a36Sopenharmony_ci	 */
149562306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_PRELOAD) &&
149662306a36Sopenharmony_ci	    dispc->feat->set_max_preload && plane != OMAP_DSS_WB)
149762306a36Sopenharmony_ci		dispc_write_reg(dispc, DISPC_OVL_PRELOAD(plane),
149862306a36Sopenharmony_ci				min(high, 0xfffu));
149962306a36Sopenharmony_ci}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_civoid dispc_enable_fifomerge(struct dispc_device *dispc, bool enable)
150262306a36Sopenharmony_ci{
150362306a36Sopenharmony_ci	if (!dispc_has_feature(dispc, FEAT_FIFO_MERGE)) {
150462306a36Sopenharmony_ci		WARN_ON(enable);
150562306a36Sopenharmony_ci		return;
150662306a36Sopenharmony_ci	}
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
150962306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_CONFIG, enable ? 1 : 0, 14, 14);
151062306a36Sopenharmony_ci}
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_civoid dispc_ovl_compute_fifo_thresholds(struct dispc_device *dispc,
151362306a36Sopenharmony_ci				       enum omap_plane_id plane,
151462306a36Sopenharmony_ci				       u32 *fifo_low, u32 *fifo_high,
151562306a36Sopenharmony_ci				       bool use_fifomerge, bool manual_update)
151662306a36Sopenharmony_ci{
151762306a36Sopenharmony_ci	/*
151862306a36Sopenharmony_ci	 * All sizes are in bytes. Both the buffer and burst are made of
151962306a36Sopenharmony_ci	 * buffer_units, and the fifo thresholds must be buffer_unit aligned.
152062306a36Sopenharmony_ci	 */
152162306a36Sopenharmony_ci	unsigned int buf_unit = dispc->feat->buffer_size_unit;
152262306a36Sopenharmony_ci	unsigned int ovl_fifo_size, total_fifo_size, burst_size;
152362306a36Sopenharmony_ci	int i;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	burst_size = dispc_ovl_get_burst_size(dispc, plane);
152662306a36Sopenharmony_ci	ovl_fifo_size = dispc_ovl_get_fifo_size(dispc, plane);
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	if (use_fifomerge) {
152962306a36Sopenharmony_ci		total_fifo_size = 0;
153062306a36Sopenharmony_ci		for (i = 0; i < dispc_get_num_ovls(dispc); ++i)
153162306a36Sopenharmony_ci			total_fifo_size += dispc_ovl_get_fifo_size(dispc, i);
153262306a36Sopenharmony_ci	} else {
153362306a36Sopenharmony_ci		total_fifo_size = ovl_fifo_size;
153462306a36Sopenharmony_ci	}
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	/*
153762306a36Sopenharmony_ci	 * We use the same low threshold for both fifomerge and non-fifomerge
153862306a36Sopenharmony_ci	 * cases, but for fifomerge we calculate the high threshold using the
153962306a36Sopenharmony_ci	 * combined fifo size
154062306a36Sopenharmony_ci	 */
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	if (manual_update && dispc_has_feature(dispc, FEAT_OMAP3_DSI_FIFO_BUG)) {
154362306a36Sopenharmony_ci		*fifo_low = ovl_fifo_size - burst_size * 2;
154462306a36Sopenharmony_ci		*fifo_high = total_fifo_size - burst_size;
154562306a36Sopenharmony_ci	} else if (plane == OMAP_DSS_WB) {
154662306a36Sopenharmony_ci		/*
154762306a36Sopenharmony_ci		 * Most optimal configuration for writeback is to push out data
154862306a36Sopenharmony_ci		 * to the interconnect the moment writeback pushes enough pixels
154962306a36Sopenharmony_ci		 * in the FIFO to form a burst
155062306a36Sopenharmony_ci		 */
155162306a36Sopenharmony_ci		*fifo_low = 0;
155262306a36Sopenharmony_ci		*fifo_high = burst_size;
155362306a36Sopenharmony_ci	} else {
155462306a36Sopenharmony_ci		*fifo_low = ovl_fifo_size - burst_size;
155562306a36Sopenharmony_ci		*fifo_high = total_fifo_size - buf_unit;
155662306a36Sopenharmony_ci	}
155762306a36Sopenharmony_ci}
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_cistatic void dispc_ovl_set_mflag(struct dispc_device *dispc,
156062306a36Sopenharmony_ci				enum omap_plane_id plane, bool enable)
156162306a36Sopenharmony_ci{
156262306a36Sopenharmony_ci	int bit;
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	if (plane == OMAP_DSS_GFX)
156562306a36Sopenharmony_ci		bit = 14;
156662306a36Sopenharmony_ci	else
156762306a36Sopenharmony_ci		bit = 23;
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit);
157062306a36Sopenharmony_ci}
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_cistatic void dispc_ovl_set_mflag_threshold(struct dispc_device *dispc,
157362306a36Sopenharmony_ci					  enum omap_plane_id plane,
157462306a36Sopenharmony_ci					  int low, int high)
157562306a36Sopenharmony_ci{
157662306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_MFLAG_THRESHOLD(plane),
157762306a36Sopenharmony_ci		FLD_VAL(high, 31, 16) |	FLD_VAL(low, 15, 0));
157862306a36Sopenharmony_ci}
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_cistatic void dispc_init_mflag(struct dispc_device *dispc)
158162306a36Sopenharmony_ci{
158262306a36Sopenharmony_ci	int i;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	/*
158562306a36Sopenharmony_ci	 * HACK: NV12 color format and MFLAG seem to have problems working
158662306a36Sopenharmony_ci	 * together: using two displays, and having an NV12 overlay on one of
158762306a36Sopenharmony_ci	 * the displays will cause underflows/synclosts when MFLAG_CTRL=2.
158862306a36Sopenharmony_ci	 * Changing MFLAG thresholds and PRELOAD to certain values seem to
158962306a36Sopenharmony_ci	 * remove the errors, but there doesn't seem to be a clear logic on
159062306a36Sopenharmony_ci	 * which values work and which not.
159162306a36Sopenharmony_ci	 *
159262306a36Sopenharmony_ci	 * As a work-around, set force MFLAG to always on.
159362306a36Sopenharmony_ci	 */
159462306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE,
159562306a36Sopenharmony_ci		(1 << 0) |	/* MFLAG_CTRL = force always on */
159662306a36Sopenharmony_ci		(0 << 2));	/* MFLAG_START = disable */
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	for (i = 0; i < dispc_get_num_ovls(dispc); ++i) {
159962306a36Sopenharmony_ci		u32 size = dispc_ovl_get_fifo_size(dispc, i);
160062306a36Sopenharmony_ci		u32 unit = dispc->feat->buffer_size_unit;
160162306a36Sopenharmony_ci		u32 low, high;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci		dispc_ovl_set_mflag(dispc, i, true);
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci		/*
160662306a36Sopenharmony_ci		 * Simulation team suggests below thesholds:
160762306a36Sopenharmony_ci		 * HT = fifosize * 5 / 8;
160862306a36Sopenharmony_ci		 * LT = fifosize * 4 / 8;
160962306a36Sopenharmony_ci		 */
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci		low = size * 4 / 8 / unit;
161262306a36Sopenharmony_ci		high = size * 5 / 8 / unit;
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci		dispc_ovl_set_mflag_threshold(dispc, i, low, high);
161562306a36Sopenharmony_ci	}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	if (dispc->feat->has_writeback) {
161862306a36Sopenharmony_ci		u32 size = dispc_ovl_get_fifo_size(dispc, OMAP_DSS_WB);
161962306a36Sopenharmony_ci		u32 unit = dispc->feat->buffer_size_unit;
162062306a36Sopenharmony_ci		u32 low, high;
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci		dispc_ovl_set_mflag(dispc, OMAP_DSS_WB, true);
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci		/*
162562306a36Sopenharmony_ci		 * Simulation team suggests below thesholds:
162662306a36Sopenharmony_ci		 * HT = fifosize * 5 / 8;
162762306a36Sopenharmony_ci		 * LT = fifosize * 4 / 8;
162862306a36Sopenharmony_ci		 */
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci		low = size * 4 / 8 / unit;
163162306a36Sopenharmony_ci		high = size * 5 / 8 / unit;
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci		dispc_ovl_set_mflag_threshold(dispc, OMAP_DSS_WB, low, high);
163462306a36Sopenharmony_ci	}
163562306a36Sopenharmony_ci}
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_cistatic void dispc_ovl_set_fir(struct dispc_device *dispc,
163862306a36Sopenharmony_ci			      enum omap_plane_id plane,
163962306a36Sopenharmony_ci			      int hinc, int vinc,
164062306a36Sopenharmony_ci			      enum omap_color_component color_comp)
164162306a36Sopenharmony_ci{
164262306a36Sopenharmony_ci	u32 val;
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
164562306a36Sopenharmony_ci		u8 hinc_start, hinc_end, vinc_start, vinc_end;
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci		dispc_get_reg_field(dispc, FEAT_REG_FIRHINC,
164862306a36Sopenharmony_ci				    &hinc_start, &hinc_end);
164962306a36Sopenharmony_ci		dispc_get_reg_field(dispc, FEAT_REG_FIRVINC,
165062306a36Sopenharmony_ci				    &vinc_start, &vinc_end);
165162306a36Sopenharmony_ci		val = FLD_VAL(vinc, vinc_start, vinc_end) |
165262306a36Sopenharmony_ci				FLD_VAL(hinc, hinc_start, hinc_end);
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci		dispc_write_reg(dispc, DISPC_OVL_FIR(plane), val);
165562306a36Sopenharmony_ci	} else {
165662306a36Sopenharmony_ci		val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
165762306a36Sopenharmony_ci		dispc_write_reg(dispc, DISPC_OVL_FIR2(plane), val);
165862306a36Sopenharmony_ci	}
165962306a36Sopenharmony_ci}
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_cistatic void dispc_ovl_set_vid_accu0(struct dispc_device *dispc,
166262306a36Sopenharmony_ci				    enum omap_plane_id plane, int haccu,
166362306a36Sopenharmony_ci				    int vaccu)
166462306a36Sopenharmony_ci{
166562306a36Sopenharmony_ci	u32 val;
166662306a36Sopenharmony_ci	u8 hor_start, hor_end, vert_start, vert_end;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	dispc_get_reg_field(dispc, FEAT_REG_HORIZONTALACCU,
166962306a36Sopenharmony_ci			    &hor_start, &hor_end);
167062306a36Sopenharmony_ci	dispc_get_reg_field(dispc, FEAT_REG_VERTICALACCU,
167162306a36Sopenharmony_ci			    &vert_start, &vert_end);
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	val = FLD_VAL(vaccu, vert_start, vert_end) |
167462306a36Sopenharmony_ci			FLD_VAL(haccu, hor_start, hor_end);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_ACCU0(plane), val);
167762306a36Sopenharmony_ci}
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_cistatic void dispc_ovl_set_vid_accu1(struct dispc_device *dispc,
168062306a36Sopenharmony_ci				    enum omap_plane_id plane, int haccu,
168162306a36Sopenharmony_ci				    int vaccu)
168262306a36Sopenharmony_ci{
168362306a36Sopenharmony_ci	u32 val;
168462306a36Sopenharmony_ci	u8 hor_start, hor_end, vert_start, vert_end;
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	dispc_get_reg_field(dispc, FEAT_REG_HORIZONTALACCU,
168762306a36Sopenharmony_ci			    &hor_start, &hor_end);
168862306a36Sopenharmony_ci	dispc_get_reg_field(dispc, FEAT_REG_VERTICALACCU,
168962306a36Sopenharmony_ci			    &vert_start, &vert_end);
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	val = FLD_VAL(vaccu, vert_start, vert_end) |
169262306a36Sopenharmony_ci			FLD_VAL(haccu, hor_start, hor_end);
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_ACCU1(plane), val);
169562306a36Sopenharmony_ci}
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_cistatic void dispc_ovl_set_vid_accu2_0(struct dispc_device *dispc,
169862306a36Sopenharmony_ci				      enum omap_plane_id plane, int haccu,
169962306a36Sopenharmony_ci				      int vaccu)
170062306a36Sopenharmony_ci{
170162306a36Sopenharmony_ci	u32 val;
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci	val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
170462306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_ACCU2_0(plane), val);
170562306a36Sopenharmony_ci}
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_cistatic void dispc_ovl_set_vid_accu2_1(struct dispc_device *dispc,
170862306a36Sopenharmony_ci				      enum omap_plane_id plane, int haccu,
170962306a36Sopenharmony_ci				      int vaccu)
171062306a36Sopenharmony_ci{
171162306a36Sopenharmony_ci	u32 val;
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
171462306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_ACCU2_1(plane), val);
171562306a36Sopenharmony_ci}
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_cistatic void dispc_ovl_set_scale_param(struct dispc_device *dispc,
171862306a36Sopenharmony_ci				      enum omap_plane_id plane,
171962306a36Sopenharmony_ci				      u16 orig_width, u16 orig_height,
172062306a36Sopenharmony_ci				      u16 out_width, u16 out_height,
172162306a36Sopenharmony_ci				      bool five_taps, u8 rotation,
172262306a36Sopenharmony_ci				      enum omap_color_component color_comp)
172362306a36Sopenharmony_ci{
172462306a36Sopenharmony_ci	int fir_hinc, fir_vinc;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	fir_hinc = 1024 * orig_width / out_width;
172762306a36Sopenharmony_ci	fir_vinc = 1024 * orig_height / out_height;
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	dispc_ovl_set_scale_coef(dispc, plane, fir_hinc, fir_vinc, five_taps,
173062306a36Sopenharmony_ci				 color_comp);
173162306a36Sopenharmony_ci	dispc_ovl_set_fir(dispc, plane, fir_hinc, fir_vinc, color_comp);
173262306a36Sopenharmony_ci}
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_cistatic void dispc_ovl_set_accu_uv(struct dispc_device *dispc,
173562306a36Sopenharmony_ci				  enum omap_plane_id plane,
173662306a36Sopenharmony_ci				  u16 orig_width, u16 orig_height,
173762306a36Sopenharmony_ci				  u16 out_width, u16 out_height,
173862306a36Sopenharmony_ci				  bool ilace, u32 fourcc, u8 rotation)
173962306a36Sopenharmony_ci{
174062306a36Sopenharmony_ci	int h_accu2_0, h_accu2_1;
174162306a36Sopenharmony_ci	int v_accu2_0, v_accu2_1;
174262306a36Sopenharmony_ci	int chroma_hinc, chroma_vinc;
174362306a36Sopenharmony_ci	int idx;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	struct accu {
174662306a36Sopenharmony_ci		s8 h0_m, h0_n;
174762306a36Sopenharmony_ci		s8 h1_m, h1_n;
174862306a36Sopenharmony_ci		s8 v0_m, v0_n;
174962306a36Sopenharmony_ci		s8 v1_m, v1_n;
175062306a36Sopenharmony_ci	};
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci	const struct accu *accu_table;
175362306a36Sopenharmony_ci	const struct accu *accu_val;
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci	static const struct accu accu_nv12[4] = {
175662306a36Sopenharmony_ci		{  0, 1,  0, 1 , -1, 2, 0, 1 },
175762306a36Sopenharmony_ci		{  1, 2, -3, 4 ,  0, 1, 0, 1 },
175862306a36Sopenharmony_ci		{ -1, 1,  0, 1 , -1, 2, 0, 1 },
175962306a36Sopenharmony_ci		{ -1, 2, -1, 2 , -1, 1, 0, 1 },
176062306a36Sopenharmony_ci	};
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	static const struct accu accu_nv12_ilace[4] = {
176362306a36Sopenharmony_ci		{  0, 1,  0, 1 , -3, 4, -1, 4 },
176462306a36Sopenharmony_ci		{ -1, 4, -3, 4 ,  0, 1,  0, 1 },
176562306a36Sopenharmony_ci		{ -1, 1,  0, 1 , -1, 4, -3, 4 },
176662306a36Sopenharmony_ci		{ -3, 4, -3, 4 , -1, 1,  0, 1 },
176762306a36Sopenharmony_ci	};
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	static const struct accu accu_yuv[4] = {
177062306a36Sopenharmony_ci		{  0, 1, 0, 1,  0, 1, 0, 1 },
177162306a36Sopenharmony_ci		{  0, 1, 0, 1,  0, 1, 0, 1 },
177262306a36Sopenharmony_ci		{ -1, 1, 0, 1,  0, 1, 0, 1 },
177362306a36Sopenharmony_ci		{  0, 1, 0, 1, -1, 1, 0, 1 },
177462306a36Sopenharmony_ci	};
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	/* Note: DSS HW rotates clockwise, DRM_MODE_ROTATE_* counter-clockwise */
177762306a36Sopenharmony_ci	switch (rotation & DRM_MODE_ROTATE_MASK) {
177862306a36Sopenharmony_ci	default:
177962306a36Sopenharmony_ci	case DRM_MODE_ROTATE_0:
178062306a36Sopenharmony_ci		idx = 0;
178162306a36Sopenharmony_ci		break;
178262306a36Sopenharmony_ci	case DRM_MODE_ROTATE_90:
178362306a36Sopenharmony_ci		idx = 3;
178462306a36Sopenharmony_ci		break;
178562306a36Sopenharmony_ci	case DRM_MODE_ROTATE_180:
178662306a36Sopenharmony_ci		idx = 2;
178762306a36Sopenharmony_ci		break;
178862306a36Sopenharmony_ci	case DRM_MODE_ROTATE_270:
178962306a36Sopenharmony_ci		idx = 1;
179062306a36Sopenharmony_ci		break;
179162306a36Sopenharmony_ci	}
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	switch (fourcc) {
179462306a36Sopenharmony_ci	case DRM_FORMAT_NV12:
179562306a36Sopenharmony_ci		if (ilace)
179662306a36Sopenharmony_ci			accu_table = accu_nv12_ilace;
179762306a36Sopenharmony_ci		else
179862306a36Sopenharmony_ci			accu_table = accu_nv12;
179962306a36Sopenharmony_ci		break;
180062306a36Sopenharmony_ci	case DRM_FORMAT_YUYV:
180162306a36Sopenharmony_ci	case DRM_FORMAT_UYVY:
180262306a36Sopenharmony_ci		accu_table = accu_yuv;
180362306a36Sopenharmony_ci		break;
180462306a36Sopenharmony_ci	default:
180562306a36Sopenharmony_ci		BUG();
180662306a36Sopenharmony_ci		return;
180762306a36Sopenharmony_ci	}
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	accu_val = &accu_table[idx];
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	chroma_hinc = 1024 * orig_width / out_width;
181262306a36Sopenharmony_ci	chroma_vinc = 1024 * orig_height / out_height;
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	h_accu2_0 = (accu_val->h0_m * chroma_hinc / accu_val->h0_n) % 1024;
181562306a36Sopenharmony_ci	h_accu2_1 = (accu_val->h1_m * chroma_hinc / accu_val->h1_n) % 1024;
181662306a36Sopenharmony_ci	v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024;
181762306a36Sopenharmony_ci	v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024;
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	dispc_ovl_set_vid_accu2_0(dispc, plane, h_accu2_0, v_accu2_0);
182062306a36Sopenharmony_ci	dispc_ovl_set_vid_accu2_1(dispc, plane, h_accu2_1, v_accu2_1);
182162306a36Sopenharmony_ci}
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_cistatic void dispc_ovl_set_scaling_common(struct dispc_device *dispc,
182462306a36Sopenharmony_ci					 enum omap_plane_id plane,
182562306a36Sopenharmony_ci					 u16 orig_width, u16 orig_height,
182662306a36Sopenharmony_ci					 u16 out_width, u16 out_height,
182762306a36Sopenharmony_ci					 bool ilace, bool five_taps,
182862306a36Sopenharmony_ci					 bool fieldmode, u32 fourcc,
182962306a36Sopenharmony_ci					 u8 rotation)
183062306a36Sopenharmony_ci{
183162306a36Sopenharmony_ci	int accu0 = 0;
183262306a36Sopenharmony_ci	int accu1 = 0;
183362306a36Sopenharmony_ci	u32 l;
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci	dispc_ovl_set_scale_param(dispc, plane, orig_width, orig_height,
183662306a36Sopenharmony_ci				  out_width, out_height, five_taps,
183762306a36Sopenharmony_ci				  rotation, DISPC_COLOR_COMPONENT_RGB_Y);
183862306a36Sopenharmony_ci	l = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane));
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	/* RESIZEENABLE and VERTICALTAPS */
184162306a36Sopenharmony_ci	l &= ~((0x3 << 5) | (0x1 << 21));
184262306a36Sopenharmony_ci	l |= (orig_width != out_width) ? (1 << 5) : 0;
184362306a36Sopenharmony_ci	l |= (orig_height != out_height) ? (1 << 6) : 0;
184462306a36Sopenharmony_ci	l |= five_taps ? (1 << 21) : 0;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	/* VRESIZECONF and HRESIZECONF */
184762306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_RESIZECONF)) {
184862306a36Sopenharmony_ci		l &= ~(0x3 << 7);
184962306a36Sopenharmony_ci		l |= (orig_width <= out_width) ? 0 : (1 << 7);
185062306a36Sopenharmony_ci		l |= (orig_height <= out_height) ? 0 : (1 << 8);
185162306a36Sopenharmony_ci	}
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	/* LINEBUFFERSPLIT */
185462306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_LINEBUFFERSPLIT)) {
185562306a36Sopenharmony_ci		l &= ~(0x1 << 22);
185662306a36Sopenharmony_ci		l |= five_taps ? (1 << 22) : 0;
185762306a36Sopenharmony_ci	}
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), l);
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	/*
186262306a36Sopenharmony_ci	 * field 0 = even field = bottom field
186362306a36Sopenharmony_ci	 * field 1 = odd field = top field
186462306a36Sopenharmony_ci	 */
186562306a36Sopenharmony_ci	if (ilace && !fieldmode) {
186662306a36Sopenharmony_ci		accu1 = 0;
186762306a36Sopenharmony_ci		accu0 = ((1024 * orig_height / out_height) / 2) & 0x3ff;
186862306a36Sopenharmony_ci		if (accu0 >= 1024/2) {
186962306a36Sopenharmony_ci			accu1 = 1024/2;
187062306a36Sopenharmony_ci			accu0 -= accu1;
187162306a36Sopenharmony_ci		}
187262306a36Sopenharmony_ci	}
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	dispc_ovl_set_vid_accu0(dispc, plane, 0, accu0);
187562306a36Sopenharmony_ci	dispc_ovl_set_vid_accu1(dispc, plane, 0, accu1);
187662306a36Sopenharmony_ci}
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_cistatic void dispc_ovl_set_scaling_uv(struct dispc_device *dispc,
187962306a36Sopenharmony_ci				     enum omap_plane_id plane,
188062306a36Sopenharmony_ci				     u16 orig_width, u16 orig_height,
188162306a36Sopenharmony_ci				     u16 out_width, u16 out_height,
188262306a36Sopenharmony_ci				     bool ilace, bool five_taps,
188362306a36Sopenharmony_ci				     bool fieldmode, u32 fourcc,
188462306a36Sopenharmony_ci				     u8 rotation)
188562306a36Sopenharmony_ci{
188662306a36Sopenharmony_ci	int scale_x = out_width != orig_width;
188762306a36Sopenharmony_ci	int scale_y = out_height != orig_height;
188862306a36Sopenharmony_ci	bool chroma_upscale = plane != OMAP_DSS_WB;
188962306a36Sopenharmony_ci	const struct drm_format_info *info;
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	info = drm_format_info(fourcc);
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	if (!dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE))
189462306a36Sopenharmony_ci		return;
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	if (!info->is_yuv) {
189762306a36Sopenharmony_ci		/* reset chroma resampling for RGB formats  */
189862306a36Sopenharmony_ci		if (plane != OMAP_DSS_WB)
189962306a36Sopenharmony_ci			REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane),
190062306a36Sopenharmony_ci				    0, 8, 8);
190162306a36Sopenharmony_ci		return;
190262306a36Sopenharmony_ci	}
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	dispc_ovl_set_accu_uv(dispc, plane, orig_width, orig_height, out_width,
190562306a36Sopenharmony_ci			      out_height, ilace, fourcc, rotation);
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	switch (fourcc) {
190862306a36Sopenharmony_ci	case DRM_FORMAT_NV12:
190962306a36Sopenharmony_ci		if (chroma_upscale) {
191062306a36Sopenharmony_ci			/* UV is subsampled by 2 horizontally and vertically */
191162306a36Sopenharmony_ci			orig_height >>= 1;
191262306a36Sopenharmony_ci			orig_width >>= 1;
191362306a36Sopenharmony_ci		} else {
191462306a36Sopenharmony_ci			/* UV is downsampled by 2 horizontally and vertically */
191562306a36Sopenharmony_ci			orig_height <<= 1;
191662306a36Sopenharmony_ci			orig_width <<= 1;
191762306a36Sopenharmony_ci		}
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci		break;
192062306a36Sopenharmony_ci	case DRM_FORMAT_YUYV:
192162306a36Sopenharmony_ci	case DRM_FORMAT_UYVY:
192262306a36Sopenharmony_ci		/* For YUV422 with 90/270 rotation, we don't upsample chroma */
192362306a36Sopenharmony_ci		if (!drm_rotation_90_or_270(rotation)) {
192462306a36Sopenharmony_ci			if (chroma_upscale)
192562306a36Sopenharmony_ci				/* UV is subsampled by 2 horizontally */
192662306a36Sopenharmony_ci				orig_width >>= 1;
192762306a36Sopenharmony_ci			else
192862306a36Sopenharmony_ci				/* UV is downsampled by 2 horizontally */
192962306a36Sopenharmony_ci				orig_width <<= 1;
193062306a36Sopenharmony_ci		}
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci		/* must use FIR for YUV422 if rotated */
193362306a36Sopenharmony_ci		if ((rotation & DRM_MODE_ROTATE_MASK) != DRM_MODE_ROTATE_0)
193462306a36Sopenharmony_ci			scale_x = scale_y = true;
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci		break;
193762306a36Sopenharmony_ci	default:
193862306a36Sopenharmony_ci		BUG();
193962306a36Sopenharmony_ci		return;
194062306a36Sopenharmony_ci	}
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	if (out_width != orig_width)
194362306a36Sopenharmony_ci		scale_x = true;
194462306a36Sopenharmony_ci	if (out_height != orig_height)
194562306a36Sopenharmony_ci		scale_y = true;
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	dispc_ovl_set_scale_param(dispc, plane, orig_width, orig_height,
194862306a36Sopenharmony_ci				  out_width, out_height, five_taps,
194962306a36Sopenharmony_ci				  rotation, DISPC_COLOR_COMPONENT_UV);
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	if (plane != OMAP_DSS_WB)
195262306a36Sopenharmony_ci		REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane),
195362306a36Sopenharmony_ci			(scale_x || scale_y) ? 1 : 0, 8, 8);
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	/* set H scaling */
195662306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5);
195762306a36Sopenharmony_ci	/* set V scaling */
195862306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6);
195962306a36Sopenharmony_ci}
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_cistatic void dispc_ovl_set_scaling(struct dispc_device *dispc,
196262306a36Sopenharmony_ci				  enum omap_plane_id plane,
196362306a36Sopenharmony_ci				  u16 orig_width, u16 orig_height,
196462306a36Sopenharmony_ci				  u16 out_width, u16 out_height,
196562306a36Sopenharmony_ci				  bool ilace, bool five_taps,
196662306a36Sopenharmony_ci				  bool fieldmode, u32 fourcc,
196762306a36Sopenharmony_ci				  u8 rotation)
196862306a36Sopenharmony_ci{
196962306a36Sopenharmony_ci	BUG_ON(plane == OMAP_DSS_GFX);
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_ci	dispc_ovl_set_scaling_common(dispc, plane, orig_width, orig_height,
197262306a36Sopenharmony_ci				     out_width, out_height, ilace, five_taps,
197362306a36Sopenharmony_ci				     fieldmode, fourcc, rotation);
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci	dispc_ovl_set_scaling_uv(dispc, plane, orig_width, orig_height,
197662306a36Sopenharmony_ci				 out_width, out_height, ilace, five_taps,
197762306a36Sopenharmony_ci				 fieldmode, fourcc, rotation);
197862306a36Sopenharmony_ci}
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_cistatic void dispc_ovl_set_rotation_attrs(struct dispc_device *dispc,
198162306a36Sopenharmony_ci					 enum omap_plane_id plane, u8 rotation,
198262306a36Sopenharmony_ci					 enum omap_dss_rotation_type rotation_type,
198362306a36Sopenharmony_ci					 u32 fourcc)
198462306a36Sopenharmony_ci{
198562306a36Sopenharmony_ci	bool row_repeat = false;
198662306a36Sopenharmony_ci	int vidrot = 0;
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	/* Note: DSS HW rotates clockwise, DRM_MODE_ROTATE_* counter-clockwise */
198962306a36Sopenharmony_ci	if (fourcc == DRM_FORMAT_YUYV || fourcc == DRM_FORMAT_UYVY) {
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci		if (rotation & DRM_MODE_REFLECT_X) {
199262306a36Sopenharmony_ci			switch (rotation & DRM_MODE_ROTATE_MASK) {
199362306a36Sopenharmony_ci			case DRM_MODE_ROTATE_0:
199462306a36Sopenharmony_ci				vidrot = 2;
199562306a36Sopenharmony_ci				break;
199662306a36Sopenharmony_ci			case DRM_MODE_ROTATE_90:
199762306a36Sopenharmony_ci				vidrot = 1;
199862306a36Sopenharmony_ci				break;
199962306a36Sopenharmony_ci			case DRM_MODE_ROTATE_180:
200062306a36Sopenharmony_ci				vidrot = 0;
200162306a36Sopenharmony_ci				break;
200262306a36Sopenharmony_ci			case DRM_MODE_ROTATE_270:
200362306a36Sopenharmony_ci				vidrot = 3;
200462306a36Sopenharmony_ci				break;
200562306a36Sopenharmony_ci			}
200662306a36Sopenharmony_ci		} else {
200762306a36Sopenharmony_ci			switch (rotation & DRM_MODE_ROTATE_MASK) {
200862306a36Sopenharmony_ci			case DRM_MODE_ROTATE_0:
200962306a36Sopenharmony_ci				vidrot = 0;
201062306a36Sopenharmony_ci				break;
201162306a36Sopenharmony_ci			case DRM_MODE_ROTATE_90:
201262306a36Sopenharmony_ci				vidrot = 3;
201362306a36Sopenharmony_ci				break;
201462306a36Sopenharmony_ci			case DRM_MODE_ROTATE_180:
201562306a36Sopenharmony_ci				vidrot = 2;
201662306a36Sopenharmony_ci				break;
201762306a36Sopenharmony_ci			case DRM_MODE_ROTATE_270:
201862306a36Sopenharmony_ci				vidrot = 1;
201962306a36Sopenharmony_ci				break;
202062306a36Sopenharmony_ci			}
202162306a36Sopenharmony_ci		}
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci		if (drm_rotation_90_or_270(rotation))
202462306a36Sopenharmony_ci			row_repeat = true;
202562306a36Sopenharmony_ci		else
202662306a36Sopenharmony_ci			row_repeat = false;
202762306a36Sopenharmony_ci	}
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	/*
203062306a36Sopenharmony_ci	 * OMAP4/5 Errata i631:
203162306a36Sopenharmony_ci	 * NV12 in 1D mode must use ROTATION=1. Otherwise DSS will fetch extra
203262306a36Sopenharmony_ci	 * rows beyond the framebuffer, which may cause OCP error.
203362306a36Sopenharmony_ci	 */
203462306a36Sopenharmony_ci	if (fourcc == DRM_FORMAT_NV12 && rotation_type != OMAP_DSS_ROT_TILER)
203562306a36Sopenharmony_ci		vidrot = 1;
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12);
203862306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_ROWREPEATENABLE))
203962306a36Sopenharmony_ci		REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane),
204062306a36Sopenharmony_ci			row_repeat ? 1 : 0, 18, 18);
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	if (dispc_ovl_color_mode_supported(dispc, plane, DRM_FORMAT_NV12)) {
204362306a36Sopenharmony_ci		bool doublestride =
204462306a36Sopenharmony_ci			fourcc == DRM_FORMAT_NV12 &&
204562306a36Sopenharmony_ci			rotation_type == OMAP_DSS_ROT_TILER &&
204662306a36Sopenharmony_ci			!drm_rotation_90_or_270(rotation);
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci		/* DOUBLESTRIDE */
204962306a36Sopenharmony_ci		REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane),
205062306a36Sopenharmony_ci			    doublestride, 22, 22);
205162306a36Sopenharmony_ci	}
205262306a36Sopenharmony_ci}
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_cistatic int color_mode_to_bpp(u32 fourcc)
205562306a36Sopenharmony_ci{
205662306a36Sopenharmony_ci	switch (fourcc) {
205762306a36Sopenharmony_ci	case DRM_FORMAT_NV12:
205862306a36Sopenharmony_ci		return 8;
205962306a36Sopenharmony_ci	case DRM_FORMAT_RGBX4444:
206062306a36Sopenharmony_ci	case DRM_FORMAT_RGB565:
206162306a36Sopenharmony_ci	case DRM_FORMAT_ARGB4444:
206262306a36Sopenharmony_ci	case DRM_FORMAT_YUYV:
206362306a36Sopenharmony_ci	case DRM_FORMAT_UYVY:
206462306a36Sopenharmony_ci	case DRM_FORMAT_RGBA4444:
206562306a36Sopenharmony_ci	case DRM_FORMAT_XRGB4444:
206662306a36Sopenharmony_ci	case DRM_FORMAT_ARGB1555:
206762306a36Sopenharmony_ci	case DRM_FORMAT_XRGB1555:
206862306a36Sopenharmony_ci		return 16;
206962306a36Sopenharmony_ci	case DRM_FORMAT_RGB888:
207062306a36Sopenharmony_ci		return 24;
207162306a36Sopenharmony_ci	case DRM_FORMAT_XRGB8888:
207262306a36Sopenharmony_ci	case DRM_FORMAT_ARGB8888:
207362306a36Sopenharmony_ci	case DRM_FORMAT_RGBA8888:
207462306a36Sopenharmony_ci	case DRM_FORMAT_RGBX8888:
207562306a36Sopenharmony_ci		return 32;
207662306a36Sopenharmony_ci	default:
207762306a36Sopenharmony_ci		BUG();
207862306a36Sopenharmony_ci		return 0;
207962306a36Sopenharmony_ci	}
208062306a36Sopenharmony_ci}
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_cistatic s32 pixinc(int pixels, u8 ps)
208362306a36Sopenharmony_ci{
208462306a36Sopenharmony_ci	if (pixels == 1)
208562306a36Sopenharmony_ci		return 1;
208662306a36Sopenharmony_ci	else if (pixels > 1)
208762306a36Sopenharmony_ci		return 1 + (pixels - 1) * ps;
208862306a36Sopenharmony_ci	else if (pixels < 0)
208962306a36Sopenharmony_ci		return 1 - (-pixels + 1) * ps;
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	BUG();
209262306a36Sopenharmony_ci}
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_cistatic void calc_offset(u16 screen_width, u16 width,
209562306a36Sopenharmony_ci		u32 fourcc, bool fieldmode, unsigned int field_offset,
209662306a36Sopenharmony_ci		unsigned int *offset0, unsigned int *offset1,
209762306a36Sopenharmony_ci		s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim,
209862306a36Sopenharmony_ci		enum omap_dss_rotation_type rotation_type, u8 rotation)
209962306a36Sopenharmony_ci{
210062306a36Sopenharmony_ci	u8 ps;
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	ps = color_mode_to_bpp(fourcc) / 8;
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	DSSDBG("scrw %d, width %d\n", screen_width, width);
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	if (rotation_type == OMAP_DSS_ROT_TILER &&
210762306a36Sopenharmony_ci	    (fourcc == DRM_FORMAT_UYVY || fourcc == DRM_FORMAT_YUYV) &&
210862306a36Sopenharmony_ci	    drm_rotation_90_or_270(rotation)) {
210962306a36Sopenharmony_ci		/*
211062306a36Sopenharmony_ci		 * HACK: ROW_INC needs to be calculated with TILER units.
211162306a36Sopenharmony_ci		 * We get such 'screen_width' that multiplying it with the
211262306a36Sopenharmony_ci		 * YUV422 pixel size gives the correct TILER container width.
211362306a36Sopenharmony_ci		 * However, 'width' is in pixels and multiplying it with YUV422
211462306a36Sopenharmony_ci		 * pixel size gives incorrect result. We thus multiply it here
211562306a36Sopenharmony_ci		 * with 2 to match the 32 bit TILER unit size.
211662306a36Sopenharmony_ci		 */
211762306a36Sopenharmony_ci		width *= 2;
211862306a36Sopenharmony_ci	}
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	/*
212162306a36Sopenharmony_ci	 * field 0 = even field = bottom field
212262306a36Sopenharmony_ci	 * field 1 = odd field = top field
212362306a36Sopenharmony_ci	 */
212462306a36Sopenharmony_ci	*offset0 = field_offset * screen_width * ps;
212562306a36Sopenharmony_ci	*offset1 = 0;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	*row_inc = pixinc(1 + (y_predecim * screen_width - width * x_predecim) +
212862306a36Sopenharmony_ci			(fieldmode ? screen_width : 0), ps);
212962306a36Sopenharmony_ci	if (fourcc == DRM_FORMAT_YUYV || fourcc == DRM_FORMAT_UYVY)
213062306a36Sopenharmony_ci		*pix_inc = pixinc(x_predecim, 2 * ps);
213162306a36Sopenharmony_ci	else
213262306a36Sopenharmony_ci		*pix_inc = pixinc(x_predecim, ps);
213362306a36Sopenharmony_ci}
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci/*
213662306a36Sopenharmony_ci * This function is used to avoid synclosts in OMAP3, because of some
213762306a36Sopenharmony_ci * undocumented horizontal position and timing related limitations.
213862306a36Sopenharmony_ci */
213962306a36Sopenharmony_cistatic int check_horiz_timing_omap3(unsigned long pclk, unsigned long lclk,
214062306a36Sopenharmony_ci		const struct videomode *vm, u16 pos_x,
214162306a36Sopenharmony_ci		u16 width, u16 height, u16 out_width, u16 out_height,
214262306a36Sopenharmony_ci		bool five_taps)
214362306a36Sopenharmony_ci{
214462306a36Sopenharmony_ci	const int ds = DIV_ROUND_UP(height, out_height);
214562306a36Sopenharmony_ci	unsigned long nonactive;
214662306a36Sopenharmony_ci	static const u8 limits[3] = { 8, 10, 20 };
214762306a36Sopenharmony_ci	u64 val, blank;
214862306a36Sopenharmony_ci	int i;
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	nonactive = vm->hactive + vm->hfront_porch + vm->hsync_len +
215162306a36Sopenharmony_ci		    vm->hback_porch - out_width;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	i = 0;
215462306a36Sopenharmony_ci	if (out_height < height)
215562306a36Sopenharmony_ci		i++;
215662306a36Sopenharmony_ci	if (out_width < width)
215762306a36Sopenharmony_ci		i++;
215862306a36Sopenharmony_ci	blank = div_u64((u64)(vm->hback_porch + vm->hsync_len + vm->hfront_porch) *
215962306a36Sopenharmony_ci			lclk, pclk);
216062306a36Sopenharmony_ci	DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]);
216162306a36Sopenharmony_ci	if (blank <= limits[i])
216262306a36Sopenharmony_ci		return -EINVAL;
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	/* FIXME add checks for 3-tap filter once the limitations are known */
216562306a36Sopenharmony_ci	if (!five_taps)
216662306a36Sopenharmony_ci		return 0;
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	/*
216962306a36Sopenharmony_ci	 * Pixel data should be prepared before visible display point starts.
217062306a36Sopenharmony_ci	 * So, atleast DS-2 lines must have already been fetched by DISPC
217162306a36Sopenharmony_ci	 * during nonactive - pos_x period.
217262306a36Sopenharmony_ci	 */
217362306a36Sopenharmony_ci	val = div_u64((u64)(nonactive - pos_x) * lclk, pclk);
217462306a36Sopenharmony_ci	DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n",
217562306a36Sopenharmony_ci		val, max(0, ds - 2) * width);
217662306a36Sopenharmony_ci	if (val < max(0, ds - 2) * width)
217762306a36Sopenharmony_ci		return -EINVAL;
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	/*
218062306a36Sopenharmony_ci	 * All lines need to be refilled during the nonactive period of which
218162306a36Sopenharmony_ci	 * only one line can be loaded during the active period. So, atleast
218262306a36Sopenharmony_ci	 * DS - 1 lines should be loaded during nonactive period.
218362306a36Sopenharmony_ci	 */
218462306a36Sopenharmony_ci	val =  div_u64((u64)nonactive * lclk, pclk);
218562306a36Sopenharmony_ci	DSSDBG("nonactive * pcd  = %llu, max(0, DS - 1) * width = %d\n",
218662306a36Sopenharmony_ci		val, max(0, ds - 1) * width);
218762306a36Sopenharmony_ci	if (val < max(0, ds - 1) * width)
218862306a36Sopenharmony_ci		return -EINVAL;
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	return 0;
219162306a36Sopenharmony_ci}
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_cistatic unsigned long calc_core_clk_five_taps(unsigned long pclk,
219462306a36Sopenharmony_ci		const struct videomode *vm, u16 width,
219562306a36Sopenharmony_ci		u16 height, u16 out_width, u16 out_height,
219662306a36Sopenharmony_ci		u32 fourcc)
219762306a36Sopenharmony_ci{
219862306a36Sopenharmony_ci	u32 core_clk = 0;
219962306a36Sopenharmony_ci	u64 tmp;
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci	if (height <= out_height && width <= out_width)
220262306a36Sopenharmony_ci		return (unsigned long) pclk;
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	if (height > out_height) {
220562306a36Sopenharmony_ci		unsigned int ppl = vm->hactive;
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci		tmp = (u64)pclk * height * out_width;
220862306a36Sopenharmony_ci		do_div(tmp, 2 * out_height * ppl);
220962306a36Sopenharmony_ci		core_clk = tmp;
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci		if (height > 2 * out_height) {
221262306a36Sopenharmony_ci			if (ppl == out_width)
221362306a36Sopenharmony_ci				return 0;
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci			tmp = (u64)pclk * (height - 2 * out_height) * out_width;
221662306a36Sopenharmony_ci			do_div(tmp, 2 * out_height * (ppl - out_width));
221762306a36Sopenharmony_ci			core_clk = max_t(u32, core_clk, tmp);
221862306a36Sopenharmony_ci		}
221962306a36Sopenharmony_ci	}
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci	if (width > out_width) {
222262306a36Sopenharmony_ci		tmp = (u64)pclk * width;
222362306a36Sopenharmony_ci		do_div(tmp, out_width);
222462306a36Sopenharmony_ci		core_clk = max_t(u32, core_clk, tmp);
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci		if (fourcc == DRM_FORMAT_XRGB8888)
222762306a36Sopenharmony_ci			core_clk <<= 1;
222862306a36Sopenharmony_ci	}
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	return core_clk;
223162306a36Sopenharmony_ci}
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_cistatic unsigned long calc_core_clk_24xx(unsigned long pclk, u16 width,
223462306a36Sopenharmony_ci		u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
223562306a36Sopenharmony_ci{
223662306a36Sopenharmony_ci	if (height > out_height && width > out_width)
223762306a36Sopenharmony_ci		return pclk * 4;
223862306a36Sopenharmony_ci	else
223962306a36Sopenharmony_ci		return pclk * 2;
224062306a36Sopenharmony_ci}
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_cistatic unsigned long calc_core_clk_34xx(unsigned long pclk, u16 width,
224362306a36Sopenharmony_ci		u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
224462306a36Sopenharmony_ci{
224562306a36Sopenharmony_ci	unsigned int hf, vf;
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	/*
224862306a36Sopenharmony_ci	 * FIXME how to determine the 'A' factor
224962306a36Sopenharmony_ci	 * for the no downscaling case ?
225062306a36Sopenharmony_ci	 */
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	if (width > 3 * out_width)
225362306a36Sopenharmony_ci		hf = 4;
225462306a36Sopenharmony_ci	else if (width > 2 * out_width)
225562306a36Sopenharmony_ci		hf = 3;
225662306a36Sopenharmony_ci	else if (width > out_width)
225762306a36Sopenharmony_ci		hf = 2;
225862306a36Sopenharmony_ci	else
225962306a36Sopenharmony_ci		hf = 1;
226062306a36Sopenharmony_ci	if (height > out_height)
226162306a36Sopenharmony_ci		vf = 2;
226262306a36Sopenharmony_ci	else
226362306a36Sopenharmony_ci		vf = 1;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	return pclk * vf * hf;
226662306a36Sopenharmony_ci}
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_cistatic unsigned long calc_core_clk_44xx(unsigned long pclk, u16 width,
226962306a36Sopenharmony_ci		u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
227062306a36Sopenharmony_ci{
227162306a36Sopenharmony_ci	/*
227262306a36Sopenharmony_ci	 * If the overlay/writeback is in mem to mem mode, there are no
227362306a36Sopenharmony_ci	 * downscaling limitations with respect to pixel clock, return 1 as
227462306a36Sopenharmony_ci	 * required core clock to represent that we have sufficient enough
227562306a36Sopenharmony_ci	 * core clock to do maximum downscaling
227662306a36Sopenharmony_ci	 */
227762306a36Sopenharmony_ci	if (mem_to_mem)
227862306a36Sopenharmony_ci		return 1;
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci	if (width > out_width)
228162306a36Sopenharmony_ci		return DIV_ROUND_UP(pclk, out_width) * width;
228262306a36Sopenharmony_ci	else
228362306a36Sopenharmony_ci		return pclk;
228462306a36Sopenharmony_ci}
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_cistatic int dispc_ovl_calc_scaling_24xx(struct dispc_device *dispc,
228762306a36Sopenharmony_ci				       unsigned long pclk, unsigned long lclk,
228862306a36Sopenharmony_ci				       const struct videomode *vm,
228962306a36Sopenharmony_ci				       u16 width, u16 height,
229062306a36Sopenharmony_ci				       u16 out_width, u16 out_height,
229162306a36Sopenharmony_ci				       u32 fourcc, bool *five_taps,
229262306a36Sopenharmony_ci				       int *x_predecim, int *y_predecim,
229362306a36Sopenharmony_ci				       int *decim_x, int *decim_y,
229462306a36Sopenharmony_ci				       u16 pos_x, unsigned long *core_clk,
229562306a36Sopenharmony_ci				       bool mem_to_mem)
229662306a36Sopenharmony_ci{
229762306a36Sopenharmony_ci	int error;
229862306a36Sopenharmony_ci	u16 in_width, in_height;
229962306a36Sopenharmony_ci	int min_factor = min(*decim_x, *decim_y);
230062306a36Sopenharmony_ci	const int maxsinglelinewidth = dispc->feat->max_line_width;
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci	*five_taps = false;
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci	do {
230562306a36Sopenharmony_ci		in_height = height / *decim_y;
230662306a36Sopenharmony_ci		in_width = width / *decim_x;
230762306a36Sopenharmony_ci		*core_clk = dispc->feat->calc_core_clk(pclk, in_width,
230862306a36Sopenharmony_ci				in_height, out_width, out_height, mem_to_mem);
230962306a36Sopenharmony_ci		error = (in_width > maxsinglelinewidth || !*core_clk ||
231062306a36Sopenharmony_ci			*core_clk > dispc_core_clk_rate(dispc));
231162306a36Sopenharmony_ci		if (error) {
231262306a36Sopenharmony_ci			if (*decim_x == *decim_y) {
231362306a36Sopenharmony_ci				*decim_x = min_factor;
231462306a36Sopenharmony_ci				++*decim_y;
231562306a36Sopenharmony_ci			} else {
231662306a36Sopenharmony_ci				swap(*decim_x, *decim_y);
231762306a36Sopenharmony_ci				if (*decim_x < *decim_y)
231862306a36Sopenharmony_ci					++*decim_x;
231962306a36Sopenharmony_ci			}
232062306a36Sopenharmony_ci		}
232162306a36Sopenharmony_ci	} while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci	if (error) {
232462306a36Sopenharmony_ci		DSSERR("failed to find scaling settings\n");
232562306a36Sopenharmony_ci		return -EINVAL;
232662306a36Sopenharmony_ci	}
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci	if (in_width > maxsinglelinewidth) {
232962306a36Sopenharmony_ci		DSSERR("Cannot scale max input width exceeded\n");
233062306a36Sopenharmony_ci		return -EINVAL;
233162306a36Sopenharmony_ci	}
233262306a36Sopenharmony_ci	return 0;
233362306a36Sopenharmony_ci}
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_cistatic int dispc_ovl_calc_scaling_34xx(struct dispc_device *dispc,
233662306a36Sopenharmony_ci				       unsigned long pclk, unsigned long lclk,
233762306a36Sopenharmony_ci				       const struct videomode *vm,
233862306a36Sopenharmony_ci				       u16 width, u16 height,
233962306a36Sopenharmony_ci				       u16 out_width, u16 out_height,
234062306a36Sopenharmony_ci				       u32 fourcc, bool *five_taps,
234162306a36Sopenharmony_ci				       int *x_predecim, int *y_predecim,
234262306a36Sopenharmony_ci				       int *decim_x, int *decim_y,
234362306a36Sopenharmony_ci				       u16 pos_x, unsigned long *core_clk,
234462306a36Sopenharmony_ci				       bool mem_to_mem)
234562306a36Sopenharmony_ci{
234662306a36Sopenharmony_ci	int error;
234762306a36Sopenharmony_ci	u16 in_width, in_height;
234862306a36Sopenharmony_ci	const int maxsinglelinewidth = dispc->feat->max_line_width;
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	do {
235162306a36Sopenharmony_ci		in_height = height / *decim_y;
235262306a36Sopenharmony_ci		in_width = width / *decim_x;
235362306a36Sopenharmony_ci		*five_taps = in_height > out_height;
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci		if (in_width > maxsinglelinewidth)
235662306a36Sopenharmony_ci			if (in_height > out_height &&
235762306a36Sopenharmony_ci						in_height < out_height * 2)
235862306a36Sopenharmony_ci				*five_taps = false;
235962306a36Sopenharmony_ciagain:
236062306a36Sopenharmony_ci		if (*five_taps)
236162306a36Sopenharmony_ci			*core_clk = calc_core_clk_five_taps(pclk, vm,
236262306a36Sopenharmony_ci						in_width, in_height, out_width,
236362306a36Sopenharmony_ci						out_height, fourcc);
236462306a36Sopenharmony_ci		else
236562306a36Sopenharmony_ci			*core_clk = dispc->feat->calc_core_clk(pclk, in_width,
236662306a36Sopenharmony_ci					in_height, out_width, out_height,
236762306a36Sopenharmony_ci					mem_to_mem);
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci		error = check_horiz_timing_omap3(pclk, lclk, vm,
237062306a36Sopenharmony_ci				pos_x, in_width, in_height, out_width,
237162306a36Sopenharmony_ci				out_height, *five_taps);
237262306a36Sopenharmony_ci		if (error && *five_taps) {
237362306a36Sopenharmony_ci			*five_taps = false;
237462306a36Sopenharmony_ci			goto again;
237562306a36Sopenharmony_ci		}
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci		error = (error || in_width > maxsinglelinewidth * 2 ||
237862306a36Sopenharmony_ci			(in_width > maxsinglelinewidth && *five_taps) ||
237962306a36Sopenharmony_ci			!*core_clk || *core_clk > dispc_core_clk_rate(dispc));
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci		if (!error) {
238262306a36Sopenharmony_ci			/* verify that we're inside the limits of scaler */
238362306a36Sopenharmony_ci			if (in_width / 4 > out_width)
238462306a36Sopenharmony_ci					error = 1;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci			if (*five_taps) {
238762306a36Sopenharmony_ci				if (in_height / 4 > out_height)
238862306a36Sopenharmony_ci					error = 1;
238962306a36Sopenharmony_ci			} else {
239062306a36Sopenharmony_ci				if (in_height / 2 > out_height)
239162306a36Sopenharmony_ci					error = 1;
239262306a36Sopenharmony_ci			}
239362306a36Sopenharmony_ci		}
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci		if (error)
239662306a36Sopenharmony_ci			++*decim_y;
239762306a36Sopenharmony_ci	} while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci	if (error) {
240062306a36Sopenharmony_ci		DSSERR("failed to find scaling settings\n");
240162306a36Sopenharmony_ci		return -EINVAL;
240262306a36Sopenharmony_ci	}
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	if (check_horiz_timing_omap3(pclk, lclk, vm, pos_x, in_width,
240562306a36Sopenharmony_ci				in_height, out_width, out_height, *five_taps)) {
240662306a36Sopenharmony_ci			DSSERR("horizontal timing too tight\n");
240762306a36Sopenharmony_ci			return -EINVAL;
240862306a36Sopenharmony_ci	}
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	if (in_width > (maxsinglelinewidth * 2)) {
241162306a36Sopenharmony_ci		DSSERR("Cannot setup scaling\n");
241262306a36Sopenharmony_ci		DSSERR("width exceeds maximum width possible\n");
241362306a36Sopenharmony_ci		return -EINVAL;
241462306a36Sopenharmony_ci	}
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci	if (in_width > maxsinglelinewidth && *five_taps) {
241762306a36Sopenharmony_ci		DSSERR("cannot setup scaling with five taps\n");
241862306a36Sopenharmony_ci		return -EINVAL;
241962306a36Sopenharmony_ci	}
242062306a36Sopenharmony_ci	return 0;
242162306a36Sopenharmony_ci}
242262306a36Sopenharmony_ci
242362306a36Sopenharmony_cistatic int dispc_ovl_calc_scaling_44xx(struct dispc_device *dispc,
242462306a36Sopenharmony_ci				       unsigned long pclk, unsigned long lclk,
242562306a36Sopenharmony_ci				       const struct videomode *vm,
242662306a36Sopenharmony_ci				       u16 width, u16 height,
242762306a36Sopenharmony_ci				       u16 out_width, u16 out_height,
242862306a36Sopenharmony_ci				       u32 fourcc, bool *five_taps,
242962306a36Sopenharmony_ci				       int *x_predecim, int *y_predecim,
243062306a36Sopenharmony_ci				       int *decim_x, int *decim_y,
243162306a36Sopenharmony_ci				       u16 pos_x, unsigned long *core_clk,
243262306a36Sopenharmony_ci				       bool mem_to_mem)
243362306a36Sopenharmony_ci{
243462306a36Sopenharmony_ci	u16 in_width, in_width_max;
243562306a36Sopenharmony_ci	int decim_x_min = *decim_x;
243662306a36Sopenharmony_ci	u16 in_height = height / *decim_y;
243762306a36Sopenharmony_ci	const int maxsinglelinewidth = dispc->feat->max_line_width;
243862306a36Sopenharmony_ci	const int maxdownscale = dispc->feat->max_downscale;
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci	if (mem_to_mem) {
244162306a36Sopenharmony_ci		in_width_max = out_width * maxdownscale;
244262306a36Sopenharmony_ci	} else {
244362306a36Sopenharmony_ci		in_width_max = dispc_core_clk_rate(dispc)
244462306a36Sopenharmony_ci			     / DIV_ROUND_UP(pclk, out_width);
244562306a36Sopenharmony_ci	}
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ci	*decim_x = DIV_ROUND_UP(width, in_width_max);
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_ci	*decim_x = max(*decim_x, decim_x_min);
245062306a36Sopenharmony_ci	if (*decim_x > *x_predecim)
245162306a36Sopenharmony_ci		return -EINVAL;
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci	do {
245462306a36Sopenharmony_ci		in_width = width / *decim_x;
245562306a36Sopenharmony_ci	} while (*decim_x <= *x_predecim &&
245662306a36Sopenharmony_ci			in_width > maxsinglelinewidth && ++*decim_x);
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	if (in_width > maxsinglelinewidth) {
245962306a36Sopenharmony_ci		DSSERR("Cannot scale width exceeds max line width\n");
246062306a36Sopenharmony_ci		return -EINVAL;
246162306a36Sopenharmony_ci	}
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	if (*decim_x > 4 && fourcc != DRM_FORMAT_NV12) {
246462306a36Sopenharmony_ci		/*
246562306a36Sopenharmony_ci		 * Let's disable all scaling that requires horizontal
246662306a36Sopenharmony_ci		 * decimation with higher factor than 4, until we have
246762306a36Sopenharmony_ci		 * better estimates of what we can and can not
246862306a36Sopenharmony_ci		 * do. However, NV12 color format appears to work Ok
246962306a36Sopenharmony_ci		 * with all decimation factors.
247062306a36Sopenharmony_ci		 *
247162306a36Sopenharmony_ci		 * When decimating horizontally by more that 4 the dss
247262306a36Sopenharmony_ci		 * is not able to fetch the data in burst mode. When
247362306a36Sopenharmony_ci		 * this happens it is hard to tell if there enough
247462306a36Sopenharmony_ci		 * bandwidth. Despite what theory says this appears to
247562306a36Sopenharmony_ci		 * be true also for 16-bit color formats.
247662306a36Sopenharmony_ci		 */
247762306a36Sopenharmony_ci		DSSERR("Not enough bandwidth, too much downscaling (x-decimation factor %d > 4)\n", *decim_x);
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci		return -EINVAL;
248062306a36Sopenharmony_ci	}
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	*core_clk = dispc->feat->calc_core_clk(pclk, in_width, in_height,
248362306a36Sopenharmony_ci				out_width, out_height, mem_to_mem);
248462306a36Sopenharmony_ci	return 0;
248562306a36Sopenharmony_ci}
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_cienum omap_overlay_caps dispc_ovl_get_caps(struct dispc_device *dispc, enum omap_plane_id plane)
248862306a36Sopenharmony_ci{
248962306a36Sopenharmony_ci	return dispc->feat->overlay_caps[plane];
249062306a36Sopenharmony_ci}
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci#define DIV_FRAC(dividend, divisor) \
249362306a36Sopenharmony_ci	((dividend) * 100 / (divisor) - ((dividend) / (divisor) * 100))
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_cistatic int dispc_ovl_calc_scaling(struct dispc_device *dispc,
249662306a36Sopenharmony_ci				  enum omap_plane_id plane,
249762306a36Sopenharmony_ci				  unsigned long pclk, unsigned long lclk,
249862306a36Sopenharmony_ci				  enum omap_overlay_caps caps,
249962306a36Sopenharmony_ci				  const struct videomode *vm,
250062306a36Sopenharmony_ci				  u16 width, u16 height,
250162306a36Sopenharmony_ci				  u16 out_width, u16 out_height,
250262306a36Sopenharmony_ci				  u32 fourcc, bool *five_taps,
250362306a36Sopenharmony_ci				  int *x_predecim, int *y_predecim, u16 pos_x,
250462306a36Sopenharmony_ci				  enum omap_dss_rotation_type rotation_type,
250562306a36Sopenharmony_ci				  bool mem_to_mem)
250662306a36Sopenharmony_ci{
250762306a36Sopenharmony_ci	int maxhdownscale = dispc->feat->max_downscale;
250862306a36Sopenharmony_ci	int maxvdownscale = dispc->feat->max_downscale;
250962306a36Sopenharmony_ci	const int max_decim_limit = 16;
251062306a36Sopenharmony_ci	unsigned long core_clk = 0;
251162306a36Sopenharmony_ci	int decim_x, decim_y, ret;
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ci	if (width == out_width && height == out_height)
251462306a36Sopenharmony_ci		return 0;
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci	if (dispc->feat->supported_scaler_color_modes) {
251762306a36Sopenharmony_ci		const u32 *modes = dispc->feat->supported_scaler_color_modes;
251862306a36Sopenharmony_ci		unsigned int i;
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci		for (i = 0; modes[i]; ++i) {
252162306a36Sopenharmony_ci			if (modes[i] == fourcc)
252262306a36Sopenharmony_ci				break;
252362306a36Sopenharmony_ci		}
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci		if (modes[i] == 0)
252662306a36Sopenharmony_ci			return -EINVAL;
252762306a36Sopenharmony_ci	}
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci	if (plane == OMAP_DSS_WB) {
253062306a36Sopenharmony_ci		switch (fourcc) {
253162306a36Sopenharmony_ci		case DRM_FORMAT_NV12:
253262306a36Sopenharmony_ci			maxhdownscale = maxvdownscale = 2;
253362306a36Sopenharmony_ci			break;
253462306a36Sopenharmony_ci		case DRM_FORMAT_YUYV:
253562306a36Sopenharmony_ci		case DRM_FORMAT_UYVY:
253662306a36Sopenharmony_ci			maxhdownscale = 2;
253762306a36Sopenharmony_ci			maxvdownscale = 4;
253862306a36Sopenharmony_ci			break;
253962306a36Sopenharmony_ci		default:
254062306a36Sopenharmony_ci			break;
254162306a36Sopenharmony_ci		}
254262306a36Sopenharmony_ci	}
254362306a36Sopenharmony_ci	if (!mem_to_mem && (pclk == 0 || vm->pixelclock == 0)) {
254462306a36Sopenharmony_ci		DSSERR("cannot calculate scaling settings: pclk is zero\n");
254562306a36Sopenharmony_ci		return -EINVAL;
254662306a36Sopenharmony_ci	}
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci	if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0)
254962306a36Sopenharmony_ci		return -EINVAL;
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci	if (mem_to_mem) {
255262306a36Sopenharmony_ci		*x_predecim = *y_predecim = 1;
255362306a36Sopenharmony_ci	} else {
255462306a36Sopenharmony_ci		*x_predecim = max_decim_limit;
255562306a36Sopenharmony_ci		*y_predecim = (rotation_type == OMAP_DSS_ROT_TILER &&
255662306a36Sopenharmony_ci				dispc_has_feature(dispc, FEAT_BURST_2D)) ?
255762306a36Sopenharmony_ci				2 : max_decim_limit;
255862306a36Sopenharmony_ci	}
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_ci	decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxhdownscale);
256162306a36Sopenharmony_ci	decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxvdownscale);
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_ci	if (decim_x > *x_predecim || out_width > width * 8)
256462306a36Sopenharmony_ci		return -EINVAL;
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	if (decim_y > *y_predecim || out_height > height * 8)
256762306a36Sopenharmony_ci		return -EINVAL;
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	ret = dispc->feat->calc_scaling(dispc, pclk, lclk, vm, width, height,
257062306a36Sopenharmony_ci					out_width, out_height, fourcc,
257162306a36Sopenharmony_ci					five_taps, x_predecim, y_predecim,
257262306a36Sopenharmony_ci					&decim_x, &decim_y, pos_x, &core_clk,
257362306a36Sopenharmony_ci					mem_to_mem);
257462306a36Sopenharmony_ci	if (ret)
257562306a36Sopenharmony_ci		return ret;
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci	DSSDBG("%dx%d -> %dx%d (%d.%02d x %d.%02d), decim %dx%d %dx%d (%d.%02d x %d.%02d), taps %d, req clk %lu, cur clk %lu\n",
257862306a36Sopenharmony_ci		width, height,
257962306a36Sopenharmony_ci		out_width, out_height,
258062306a36Sopenharmony_ci		out_width / width, DIV_FRAC(out_width, width),
258162306a36Sopenharmony_ci		out_height / height, DIV_FRAC(out_height, height),
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci		decim_x, decim_y,
258462306a36Sopenharmony_ci		width / decim_x, height / decim_y,
258562306a36Sopenharmony_ci		out_width / (width / decim_x), DIV_FRAC(out_width, width / decim_x),
258662306a36Sopenharmony_ci		out_height / (height / decim_y), DIV_FRAC(out_height, height / decim_y),
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci		*five_taps ? 5 : 3,
258962306a36Sopenharmony_ci		core_clk, dispc_core_clk_rate(dispc));
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	if (!core_clk || core_clk > dispc_core_clk_rate(dispc)) {
259262306a36Sopenharmony_ci		DSSERR("failed to set up scaling, "
259362306a36Sopenharmony_ci			"required core clk rate = %lu Hz, "
259462306a36Sopenharmony_ci			"current core clk rate = %lu Hz\n",
259562306a36Sopenharmony_ci			core_clk, dispc_core_clk_rate(dispc));
259662306a36Sopenharmony_ci		return -EINVAL;
259762306a36Sopenharmony_ci	}
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ci	*x_predecim = decim_x;
260062306a36Sopenharmony_ci	*y_predecim = decim_y;
260162306a36Sopenharmony_ci	return 0;
260262306a36Sopenharmony_ci}
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_civoid dispc_ovl_get_max_size(struct dispc_device *dispc, u16 *width, u16 *height)
260562306a36Sopenharmony_ci{
260662306a36Sopenharmony_ci	*width = dispc->feat->ovl_width_max;
260762306a36Sopenharmony_ci	*height = dispc->feat->ovl_height_max;
260862306a36Sopenharmony_ci}
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_cistatic int dispc_ovl_setup_common(struct dispc_device *dispc,
261162306a36Sopenharmony_ci				  enum omap_plane_id plane,
261262306a36Sopenharmony_ci				  enum omap_overlay_caps caps,
261362306a36Sopenharmony_ci				  u32 paddr, u32 p_uv_addr,
261462306a36Sopenharmony_ci				  u16 screen_width, int pos_x, int pos_y,
261562306a36Sopenharmony_ci				  u16 width, u16 height,
261662306a36Sopenharmony_ci				  u16 out_width, u16 out_height,
261762306a36Sopenharmony_ci				  u32 fourcc, u8 rotation, u8 zorder,
261862306a36Sopenharmony_ci				  u8 pre_mult_alpha, u8 global_alpha,
261962306a36Sopenharmony_ci				  enum omap_dss_rotation_type rotation_type,
262062306a36Sopenharmony_ci				  bool replication, const struct videomode *vm,
262162306a36Sopenharmony_ci				  bool mem_to_mem,
262262306a36Sopenharmony_ci				  enum drm_color_encoding color_encoding,
262362306a36Sopenharmony_ci				  enum drm_color_range color_range)
262462306a36Sopenharmony_ci{
262562306a36Sopenharmony_ci	bool five_taps = true;
262662306a36Sopenharmony_ci	bool fieldmode = false;
262762306a36Sopenharmony_ci	int r, cconv = 0;
262862306a36Sopenharmony_ci	unsigned int offset0, offset1;
262962306a36Sopenharmony_ci	s32 row_inc;
263062306a36Sopenharmony_ci	s32 pix_inc;
263162306a36Sopenharmony_ci	u16 frame_width;
263262306a36Sopenharmony_ci	unsigned int field_offset = 0;
263362306a36Sopenharmony_ci	u16 in_height = height;
263462306a36Sopenharmony_ci	u16 in_width = width;
263562306a36Sopenharmony_ci	int x_predecim = 1, y_predecim = 1;
263662306a36Sopenharmony_ci	bool ilace = !!(vm->flags & DISPLAY_FLAGS_INTERLACED);
263762306a36Sopenharmony_ci	unsigned long pclk = dispc_plane_pclk_rate(dispc, plane);
263862306a36Sopenharmony_ci	unsigned long lclk = dispc_plane_lclk_rate(dispc, plane);
263962306a36Sopenharmony_ci	const struct drm_format_info *info;
264062306a36Sopenharmony_ci
264162306a36Sopenharmony_ci	info = drm_format_info(fourcc);
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci	/* when setting up WB, dispc_plane_pclk_rate() returns 0 */
264462306a36Sopenharmony_ci	if (plane == OMAP_DSS_WB)
264562306a36Sopenharmony_ci		pclk = vm->pixelclock;
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci	if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER)
264862306a36Sopenharmony_ci		return -EINVAL;
264962306a36Sopenharmony_ci
265062306a36Sopenharmony_ci	if (info->is_yuv && (in_width & 1)) {
265162306a36Sopenharmony_ci		DSSERR("input width %d is not even for YUV format\n", in_width);
265262306a36Sopenharmony_ci		return -EINVAL;
265362306a36Sopenharmony_ci	}
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci	out_width = out_width == 0 ? width : out_width;
265662306a36Sopenharmony_ci	out_height = out_height == 0 ? height : out_height;
265762306a36Sopenharmony_ci
265862306a36Sopenharmony_ci	if (plane != OMAP_DSS_WB) {
265962306a36Sopenharmony_ci		if (ilace && height == out_height)
266062306a36Sopenharmony_ci			fieldmode = true;
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci		if (ilace) {
266362306a36Sopenharmony_ci			if (fieldmode)
266462306a36Sopenharmony_ci				in_height /= 2;
266562306a36Sopenharmony_ci			pos_y /= 2;
266662306a36Sopenharmony_ci			out_height /= 2;
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci			DSSDBG("adjusting for ilace: height %d, pos_y %d, out_height %d\n",
266962306a36Sopenharmony_ci				in_height, pos_y, out_height);
267062306a36Sopenharmony_ci		}
267162306a36Sopenharmony_ci	}
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_ci	if (!dispc_ovl_color_mode_supported(dispc, plane, fourcc))
267462306a36Sopenharmony_ci		return -EINVAL;
267562306a36Sopenharmony_ci
267662306a36Sopenharmony_ci	r = dispc_ovl_calc_scaling(dispc, plane, pclk, lclk, caps, vm, in_width,
267762306a36Sopenharmony_ci				   in_height, out_width, out_height, fourcc,
267862306a36Sopenharmony_ci				   &five_taps, &x_predecim, &y_predecim, pos_x,
267962306a36Sopenharmony_ci				   rotation_type, mem_to_mem);
268062306a36Sopenharmony_ci	if (r)
268162306a36Sopenharmony_ci		return r;
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci	in_width = in_width / x_predecim;
268462306a36Sopenharmony_ci	in_height = in_height / y_predecim;
268562306a36Sopenharmony_ci
268662306a36Sopenharmony_ci	if (x_predecim > 1 || y_predecim > 1)
268762306a36Sopenharmony_ci		DSSDBG("predecimation %d x %x, new input size %d x %d\n",
268862306a36Sopenharmony_ci			x_predecim, y_predecim, in_width, in_height);
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci	if (info->is_yuv && (in_width & 1)) {
269162306a36Sopenharmony_ci		DSSDBG("predecimated input width is not even for YUV format\n");
269262306a36Sopenharmony_ci		DSSDBG("adjusting input width %d -> %d\n",
269362306a36Sopenharmony_ci			in_width, in_width & ~1);
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci		in_width &= ~1;
269662306a36Sopenharmony_ci	}
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci	if (info->is_yuv)
269962306a36Sopenharmony_ci		cconv = 1;
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci	if (ilace && !fieldmode) {
270262306a36Sopenharmony_ci		/*
270362306a36Sopenharmony_ci		 * when downscaling the bottom field may have to start several
270462306a36Sopenharmony_ci		 * source lines below the top field. Unfortunately ACCUI
270562306a36Sopenharmony_ci		 * registers will only hold the fractional part of the offset
270662306a36Sopenharmony_ci		 * so the integer part must be added to the base address of the
270762306a36Sopenharmony_ci		 * bottom field.
270862306a36Sopenharmony_ci		 */
270962306a36Sopenharmony_ci		if (!in_height || in_height == out_height)
271062306a36Sopenharmony_ci			field_offset = 0;
271162306a36Sopenharmony_ci		else
271262306a36Sopenharmony_ci			field_offset = in_height / out_height / 2;
271362306a36Sopenharmony_ci	}
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_ci	/* Fields are independent but interleaved in memory. */
271662306a36Sopenharmony_ci	if (fieldmode)
271762306a36Sopenharmony_ci		field_offset = 1;
271862306a36Sopenharmony_ci
271962306a36Sopenharmony_ci	offset0 = 0;
272062306a36Sopenharmony_ci	offset1 = 0;
272162306a36Sopenharmony_ci	row_inc = 0;
272262306a36Sopenharmony_ci	pix_inc = 0;
272362306a36Sopenharmony_ci
272462306a36Sopenharmony_ci	if (plane == OMAP_DSS_WB)
272562306a36Sopenharmony_ci		frame_width = out_width;
272662306a36Sopenharmony_ci	else
272762306a36Sopenharmony_ci		frame_width = in_width;
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	calc_offset(screen_width, frame_width,
273062306a36Sopenharmony_ci			fourcc, fieldmode, field_offset,
273162306a36Sopenharmony_ci			&offset0, &offset1, &row_inc, &pix_inc,
273262306a36Sopenharmony_ci			x_predecim, y_predecim,
273362306a36Sopenharmony_ci			rotation_type, rotation);
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci	DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
273662306a36Sopenharmony_ci			offset0, offset1, row_inc, pix_inc);
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_ci	dispc_ovl_set_color_mode(dispc, plane, fourcc);
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci	dispc_ovl_configure_burst_type(dispc, plane, rotation_type);
274162306a36Sopenharmony_ci
274262306a36Sopenharmony_ci	if (dispc->feat->reverse_ilace_field_order)
274362306a36Sopenharmony_ci		swap(offset0, offset1);
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci	dispc_ovl_set_ba0(dispc, plane, paddr + offset0);
274662306a36Sopenharmony_ci	dispc_ovl_set_ba1(dispc, plane, paddr + offset1);
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_ci	if (fourcc == DRM_FORMAT_NV12) {
274962306a36Sopenharmony_ci		dispc_ovl_set_ba0_uv(dispc, plane, p_uv_addr + offset0);
275062306a36Sopenharmony_ci		dispc_ovl_set_ba1_uv(dispc, plane, p_uv_addr + offset1);
275162306a36Sopenharmony_ci	}
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ci	if (dispc->feat->last_pixel_inc_missing)
275462306a36Sopenharmony_ci		row_inc += pix_inc - 1;
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ci	dispc_ovl_set_row_inc(dispc, plane, row_inc);
275762306a36Sopenharmony_ci	dispc_ovl_set_pix_inc(dispc, plane, pix_inc);
275862306a36Sopenharmony_ci
275962306a36Sopenharmony_ci	DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width,
276062306a36Sopenharmony_ci			in_height, out_width, out_height);
276162306a36Sopenharmony_ci
276262306a36Sopenharmony_ci	dispc_ovl_set_pos(dispc, plane, caps, pos_x, pos_y);
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_ci	dispc_ovl_set_input_size(dispc, plane, in_width, in_height);
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_ci	if (caps & OMAP_DSS_OVL_CAP_SCALE) {
276762306a36Sopenharmony_ci		dispc_ovl_set_scaling(dispc, plane, in_width, in_height,
276862306a36Sopenharmony_ci				      out_width, out_height, ilace, five_taps,
276962306a36Sopenharmony_ci				      fieldmode, fourcc, rotation);
277062306a36Sopenharmony_ci		dispc_ovl_set_output_size(dispc, plane, out_width, out_height);
277162306a36Sopenharmony_ci		dispc_ovl_set_vid_color_conv(dispc, plane, cconv);
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci		if (plane != OMAP_DSS_WB)
277462306a36Sopenharmony_ci			dispc_ovl_set_csc(dispc, plane, color_encoding, color_range);
277562306a36Sopenharmony_ci	}
277662306a36Sopenharmony_ci
277762306a36Sopenharmony_ci	dispc_ovl_set_rotation_attrs(dispc, plane, rotation, rotation_type,
277862306a36Sopenharmony_ci				     fourcc);
277962306a36Sopenharmony_ci
278062306a36Sopenharmony_ci	dispc_ovl_set_zorder(dispc, plane, caps, zorder);
278162306a36Sopenharmony_ci	dispc_ovl_set_pre_mult_alpha(dispc, plane, caps, pre_mult_alpha);
278262306a36Sopenharmony_ci	dispc_ovl_setup_global_alpha(dispc, plane, caps, global_alpha);
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci	dispc_ovl_enable_replication(dispc, plane, caps, replication);
278562306a36Sopenharmony_ci
278662306a36Sopenharmony_ci	return 0;
278762306a36Sopenharmony_ci}
278862306a36Sopenharmony_ci
278962306a36Sopenharmony_ciint dispc_ovl_setup(struct dispc_device *dispc,
279062306a36Sopenharmony_ci			   enum omap_plane_id plane,
279162306a36Sopenharmony_ci			   const struct omap_overlay_info *oi,
279262306a36Sopenharmony_ci			   const struct videomode *vm, bool mem_to_mem,
279362306a36Sopenharmony_ci			   enum omap_channel channel)
279462306a36Sopenharmony_ci{
279562306a36Sopenharmony_ci	int r;
279662306a36Sopenharmony_ci	enum omap_overlay_caps caps = dispc->feat->overlay_caps[plane];
279762306a36Sopenharmony_ci	const bool replication = true;
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci	DSSDBG("dispc_ovl_setup %d, pa %pad, pa_uv %pad, sw %d, %d,%d, %dx%d ->"
280062306a36Sopenharmony_ci		" %dx%d, cmode %x, rot %d, chan %d repl %d\n",
280162306a36Sopenharmony_ci		plane, &oi->paddr, &oi->p_uv_addr, oi->screen_width, oi->pos_x,
280262306a36Sopenharmony_ci		oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height,
280362306a36Sopenharmony_ci		oi->fourcc, oi->rotation, channel, replication);
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci	dispc_ovl_set_channel_out(dispc, plane, channel);
280662306a36Sopenharmony_ci
280762306a36Sopenharmony_ci	r = dispc_ovl_setup_common(dispc, plane, caps, oi->paddr, oi->p_uv_addr,
280862306a36Sopenharmony_ci		oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
280962306a36Sopenharmony_ci		oi->out_width, oi->out_height, oi->fourcc, oi->rotation,
281062306a36Sopenharmony_ci		oi->zorder, oi->pre_mult_alpha, oi->global_alpha,
281162306a36Sopenharmony_ci		oi->rotation_type, replication, vm, mem_to_mem,
281262306a36Sopenharmony_ci		oi->color_encoding, oi->color_range);
281362306a36Sopenharmony_ci
281462306a36Sopenharmony_ci	return r;
281562306a36Sopenharmony_ci}
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ciint dispc_wb_setup(struct dispc_device *dispc,
281862306a36Sopenharmony_ci		   const struct omap_dss_writeback_info *wi,
281962306a36Sopenharmony_ci		   bool mem_to_mem, const struct videomode *vm,
282062306a36Sopenharmony_ci		   enum dss_writeback_channel channel_in)
282162306a36Sopenharmony_ci{
282262306a36Sopenharmony_ci	int r;
282362306a36Sopenharmony_ci	u32 l;
282462306a36Sopenharmony_ci	enum omap_plane_id plane = OMAP_DSS_WB;
282562306a36Sopenharmony_ci	const int pos_x = 0, pos_y = 0;
282662306a36Sopenharmony_ci	const u8 zorder = 0, global_alpha = 0;
282762306a36Sopenharmony_ci	const bool replication = true;
282862306a36Sopenharmony_ci	bool truncation;
282962306a36Sopenharmony_ci	int in_width = vm->hactive;
283062306a36Sopenharmony_ci	int in_height = vm->vactive;
283162306a36Sopenharmony_ci	enum omap_overlay_caps caps =
283262306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA;
283362306a36Sopenharmony_ci
283462306a36Sopenharmony_ci	if (vm->flags & DISPLAY_FLAGS_INTERLACED)
283562306a36Sopenharmony_ci		in_height /= 2;
283662306a36Sopenharmony_ci
283762306a36Sopenharmony_ci	DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, "
283862306a36Sopenharmony_ci		"rot %d\n", wi->paddr, wi->p_uv_addr, in_width,
283962306a36Sopenharmony_ci		in_height, wi->width, wi->height, wi->fourcc, wi->rotation);
284062306a36Sopenharmony_ci
284162306a36Sopenharmony_ci	r = dispc_ovl_setup_common(dispc, plane, caps, wi->paddr, wi->p_uv_addr,
284262306a36Sopenharmony_ci		wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width,
284362306a36Sopenharmony_ci		wi->height, wi->fourcc, wi->rotation, zorder,
284462306a36Sopenharmony_ci		wi->pre_mult_alpha, global_alpha, wi->rotation_type,
284562306a36Sopenharmony_ci		replication, vm, mem_to_mem, DRM_COLOR_YCBCR_BT601,
284662306a36Sopenharmony_ci		DRM_COLOR_YCBCR_LIMITED_RANGE);
284762306a36Sopenharmony_ci	if (r)
284862306a36Sopenharmony_ci		return r;
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	switch (wi->fourcc) {
285162306a36Sopenharmony_ci	case DRM_FORMAT_RGB565:
285262306a36Sopenharmony_ci	case DRM_FORMAT_RGB888:
285362306a36Sopenharmony_ci	case DRM_FORMAT_ARGB4444:
285462306a36Sopenharmony_ci	case DRM_FORMAT_RGBA4444:
285562306a36Sopenharmony_ci	case DRM_FORMAT_RGBX4444:
285662306a36Sopenharmony_ci	case DRM_FORMAT_ARGB1555:
285762306a36Sopenharmony_ci	case DRM_FORMAT_XRGB1555:
285862306a36Sopenharmony_ci	case DRM_FORMAT_XRGB4444:
285962306a36Sopenharmony_ci		truncation = true;
286062306a36Sopenharmony_ci		break;
286162306a36Sopenharmony_ci	default:
286262306a36Sopenharmony_ci		truncation = false;
286362306a36Sopenharmony_ci		break;
286462306a36Sopenharmony_ci	}
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_ci	/* setup extra DISPC_WB_ATTRIBUTES */
286762306a36Sopenharmony_ci	l = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane));
286862306a36Sopenharmony_ci	l = FLD_MOD(l, truncation, 10, 10);	/* TRUNCATIONENABLE */
286962306a36Sopenharmony_ci	l = FLD_MOD(l, channel_in, 18, 16);	/* CHANNELIN */
287062306a36Sopenharmony_ci	l = FLD_MOD(l, mem_to_mem, 19, 19);	/* WRITEBACKMODE */
287162306a36Sopenharmony_ci	if (mem_to_mem)
287262306a36Sopenharmony_ci		l = FLD_MOD(l, 1, 26, 24);	/* CAPTUREMODE */
287362306a36Sopenharmony_ci	else
287462306a36Sopenharmony_ci		l = FLD_MOD(l, 0, 26, 24);	/* CAPTUREMODE */
287562306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), l);
287662306a36Sopenharmony_ci
287762306a36Sopenharmony_ci	if (mem_to_mem) {
287862306a36Sopenharmony_ci		/* WBDELAYCOUNT */
287962306a36Sopenharmony_ci		REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), 0, 7, 0);
288062306a36Sopenharmony_ci	} else {
288162306a36Sopenharmony_ci		u32 wbdelay;
288262306a36Sopenharmony_ci
288362306a36Sopenharmony_ci		if (channel_in == DSS_WB_TV_MGR)
288462306a36Sopenharmony_ci			wbdelay = vm->vsync_len + vm->vback_porch;
288562306a36Sopenharmony_ci		else
288662306a36Sopenharmony_ci			wbdelay = vm->vfront_porch + vm->vsync_len +
288762306a36Sopenharmony_ci				vm->vback_porch;
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ci		if (vm->flags & DISPLAY_FLAGS_INTERLACED)
289062306a36Sopenharmony_ci			wbdelay /= 2;
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_ci		wbdelay = min(wbdelay, 255u);
289362306a36Sopenharmony_ci
289462306a36Sopenharmony_ci		/* WBDELAYCOUNT */
289562306a36Sopenharmony_ci		REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0);
289662306a36Sopenharmony_ci	}
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_ci	return 0;
289962306a36Sopenharmony_ci}
290062306a36Sopenharmony_ci
290162306a36Sopenharmony_cibool dispc_has_writeback(struct dispc_device *dispc)
290262306a36Sopenharmony_ci{
290362306a36Sopenharmony_ci	return dispc->feat->has_writeback;
290462306a36Sopenharmony_ci}
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ciint dispc_ovl_enable(struct dispc_device *dispc,
290762306a36Sopenharmony_ci			    enum omap_plane_id plane, bool enable)
290862306a36Sopenharmony_ci{
290962306a36Sopenharmony_ci	DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
291062306a36Sopenharmony_ci
291162306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
291262306a36Sopenharmony_ci
291362306a36Sopenharmony_ci	return 0;
291462306a36Sopenharmony_ci}
291562306a36Sopenharmony_ci
291662306a36Sopenharmony_cistatic void dispc_lcd_enable_signal_polarity(struct dispc_device *dispc,
291762306a36Sopenharmony_ci					     bool act_high)
291862306a36Sopenharmony_ci{
291962306a36Sopenharmony_ci	if (!dispc_has_feature(dispc, FEAT_LCDENABLEPOL))
292062306a36Sopenharmony_ci		return;
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
292362306a36Sopenharmony_ci}
292462306a36Sopenharmony_ci
292562306a36Sopenharmony_civoid dispc_lcd_enable_signal(struct dispc_device *dispc, bool enable)
292662306a36Sopenharmony_ci{
292762306a36Sopenharmony_ci	if (!dispc_has_feature(dispc, FEAT_LCDENABLESIGNAL))
292862306a36Sopenharmony_ci		return;
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_CONTROL, enable ? 1 : 0, 28, 28);
293162306a36Sopenharmony_ci}
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_civoid dispc_pck_free_enable(struct dispc_device *dispc, bool enable)
293462306a36Sopenharmony_ci{
293562306a36Sopenharmony_ci	if (!dispc_has_feature(dispc, FEAT_PCKFREEENABLE))
293662306a36Sopenharmony_ci		return;
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_CONTROL, enable ? 1 : 0, 27, 27);
293962306a36Sopenharmony_ci}
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_cistatic void dispc_mgr_enable_fifohandcheck(struct dispc_device *dispc,
294262306a36Sopenharmony_ci					   enum omap_channel channel,
294362306a36Sopenharmony_ci					   bool enable)
294462306a36Sopenharmony_ci{
294562306a36Sopenharmony_ci	mgr_fld_write(dispc, channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable);
294662306a36Sopenharmony_ci}
294762306a36Sopenharmony_ci
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_cistatic void dispc_mgr_set_lcd_type_tft(struct dispc_device *dispc,
295062306a36Sopenharmony_ci				       enum omap_channel channel)
295162306a36Sopenharmony_ci{
295262306a36Sopenharmony_ci	mgr_fld_write(dispc, channel, DISPC_MGR_FLD_STNTFT, 1);
295362306a36Sopenharmony_ci}
295462306a36Sopenharmony_ci
295562306a36Sopenharmony_cistatic void dispc_set_loadmode(struct dispc_device *dispc,
295662306a36Sopenharmony_ci			       enum omap_dss_load_mode mode)
295762306a36Sopenharmony_ci{
295862306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_CONFIG, mode, 2, 1);
295962306a36Sopenharmony_ci}
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci
296262306a36Sopenharmony_cistatic void dispc_mgr_set_default_color(struct dispc_device *dispc,
296362306a36Sopenharmony_ci					enum omap_channel channel, u32 color)
296462306a36Sopenharmony_ci{
296562306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_DEFAULT_COLOR(channel), color);
296662306a36Sopenharmony_ci}
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_cistatic void dispc_mgr_set_trans_key(struct dispc_device *dispc,
296962306a36Sopenharmony_ci				    enum omap_channel ch,
297062306a36Sopenharmony_ci				    enum omap_dss_trans_key_type type,
297162306a36Sopenharmony_ci				    u32 trans_key)
297262306a36Sopenharmony_ci{
297362306a36Sopenharmony_ci	mgr_fld_write(dispc, ch, DISPC_MGR_FLD_TCKSELECTION, type);
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_TRANS_COLOR(ch), trans_key);
297662306a36Sopenharmony_ci}
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_cistatic void dispc_mgr_enable_trans_key(struct dispc_device *dispc,
297962306a36Sopenharmony_ci				       enum omap_channel ch, bool enable)
298062306a36Sopenharmony_ci{
298162306a36Sopenharmony_ci	mgr_fld_write(dispc, ch, DISPC_MGR_FLD_TCKENABLE, enable);
298262306a36Sopenharmony_ci}
298362306a36Sopenharmony_ci
298462306a36Sopenharmony_cistatic void dispc_mgr_enable_alpha_fixed_zorder(struct dispc_device *dispc,
298562306a36Sopenharmony_ci						enum omap_channel ch,
298662306a36Sopenharmony_ci						bool enable)
298762306a36Sopenharmony_ci{
298862306a36Sopenharmony_ci	if (!dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER))
298962306a36Sopenharmony_ci		return;
299062306a36Sopenharmony_ci
299162306a36Sopenharmony_ci	if (ch == OMAP_DSS_CHANNEL_LCD)
299262306a36Sopenharmony_ci		REG_FLD_MOD(dispc, DISPC_CONFIG, enable, 18, 18);
299362306a36Sopenharmony_ci	else if (ch == OMAP_DSS_CHANNEL_DIGIT)
299462306a36Sopenharmony_ci		REG_FLD_MOD(dispc, DISPC_CONFIG, enable, 19, 19);
299562306a36Sopenharmony_ci}
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_civoid dispc_mgr_setup(struct dispc_device *dispc,
299862306a36Sopenharmony_ci			    enum omap_channel channel,
299962306a36Sopenharmony_ci			    const struct omap_overlay_manager_info *info)
300062306a36Sopenharmony_ci{
300162306a36Sopenharmony_ci	dispc_mgr_set_default_color(dispc, channel, info->default_color);
300262306a36Sopenharmony_ci	dispc_mgr_set_trans_key(dispc, channel, info->trans_key_type,
300362306a36Sopenharmony_ci				info->trans_key);
300462306a36Sopenharmony_ci	dispc_mgr_enable_trans_key(dispc, channel, info->trans_enabled);
300562306a36Sopenharmony_ci	dispc_mgr_enable_alpha_fixed_zorder(dispc, channel,
300662306a36Sopenharmony_ci			info->partial_alpha_enabled);
300762306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_CPR)) {
300862306a36Sopenharmony_ci		dispc_mgr_enable_cpr(dispc, channel, info->cpr_enable);
300962306a36Sopenharmony_ci		dispc_mgr_set_cpr_coef(dispc, channel, &info->cpr_coefs);
301062306a36Sopenharmony_ci	}
301162306a36Sopenharmony_ci}
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_cistatic void dispc_mgr_set_tft_data_lines(struct dispc_device *dispc,
301462306a36Sopenharmony_ci					 enum omap_channel channel,
301562306a36Sopenharmony_ci					 u8 data_lines)
301662306a36Sopenharmony_ci{
301762306a36Sopenharmony_ci	int code;
301862306a36Sopenharmony_ci
301962306a36Sopenharmony_ci	switch (data_lines) {
302062306a36Sopenharmony_ci	case 12:
302162306a36Sopenharmony_ci		code = 0;
302262306a36Sopenharmony_ci		break;
302362306a36Sopenharmony_ci	case 16:
302462306a36Sopenharmony_ci		code = 1;
302562306a36Sopenharmony_ci		break;
302662306a36Sopenharmony_ci	case 18:
302762306a36Sopenharmony_ci		code = 2;
302862306a36Sopenharmony_ci		break;
302962306a36Sopenharmony_ci	case 24:
303062306a36Sopenharmony_ci		code = 3;
303162306a36Sopenharmony_ci		break;
303262306a36Sopenharmony_ci	default:
303362306a36Sopenharmony_ci		BUG();
303462306a36Sopenharmony_ci		return;
303562306a36Sopenharmony_ci	}
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci	mgr_fld_write(dispc, channel, DISPC_MGR_FLD_TFTDATALINES, code);
303862306a36Sopenharmony_ci}
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_cistatic void dispc_mgr_set_io_pad_mode(struct dispc_device *dispc,
304162306a36Sopenharmony_ci				      enum dss_io_pad_mode mode)
304262306a36Sopenharmony_ci{
304362306a36Sopenharmony_ci	u32 l;
304462306a36Sopenharmony_ci	int gpout0, gpout1;
304562306a36Sopenharmony_ci
304662306a36Sopenharmony_ci	switch (mode) {
304762306a36Sopenharmony_ci	case DSS_IO_PAD_MODE_RESET:
304862306a36Sopenharmony_ci		gpout0 = 0;
304962306a36Sopenharmony_ci		gpout1 = 0;
305062306a36Sopenharmony_ci		break;
305162306a36Sopenharmony_ci	case DSS_IO_PAD_MODE_RFBI:
305262306a36Sopenharmony_ci		gpout0 = 1;
305362306a36Sopenharmony_ci		gpout1 = 0;
305462306a36Sopenharmony_ci		break;
305562306a36Sopenharmony_ci	case DSS_IO_PAD_MODE_BYPASS:
305662306a36Sopenharmony_ci		gpout0 = 1;
305762306a36Sopenharmony_ci		gpout1 = 1;
305862306a36Sopenharmony_ci		break;
305962306a36Sopenharmony_ci	default:
306062306a36Sopenharmony_ci		BUG();
306162306a36Sopenharmony_ci		return;
306262306a36Sopenharmony_ci	}
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_ci	l = dispc_read_reg(dispc, DISPC_CONTROL);
306562306a36Sopenharmony_ci	l = FLD_MOD(l, gpout0, 15, 15);
306662306a36Sopenharmony_ci	l = FLD_MOD(l, gpout1, 16, 16);
306762306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_CONTROL, l);
306862306a36Sopenharmony_ci}
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_cistatic void dispc_mgr_enable_stallmode(struct dispc_device *dispc,
307162306a36Sopenharmony_ci				       enum omap_channel channel, bool enable)
307262306a36Sopenharmony_ci{
307362306a36Sopenharmony_ci	mgr_fld_write(dispc, channel, DISPC_MGR_FLD_STALLMODE, enable);
307462306a36Sopenharmony_ci}
307562306a36Sopenharmony_ci
307662306a36Sopenharmony_civoid dispc_mgr_set_lcd_config(struct dispc_device *dispc,
307762306a36Sopenharmony_ci				     enum omap_channel channel,
307862306a36Sopenharmony_ci				     const struct dss_lcd_mgr_config *config)
307962306a36Sopenharmony_ci{
308062306a36Sopenharmony_ci	dispc_mgr_set_io_pad_mode(dispc, config->io_pad_mode);
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_ci	dispc_mgr_enable_stallmode(dispc, channel, config->stallmode);
308362306a36Sopenharmony_ci	dispc_mgr_enable_fifohandcheck(dispc, channel, config->fifohandcheck);
308462306a36Sopenharmony_ci
308562306a36Sopenharmony_ci	dispc_mgr_set_clock_div(dispc, channel, &config->clock_info);
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_ci	dispc_mgr_set_tft_data_lines(dispc, channel, config->video_port_width);
308862306a36Sopenharmony_ci
308962306a36Sopenharmony_ci	dispc_lcd_enable_signal_polarity(dispc, config->lcden_sig_polarity);
309062306a36Sopenharmony_ci
309162306a36Sopenharmony_ci	dispc_mgr_set_lcd_type_tft(dispc, channel);
309262306a36Sopenharmony_ci}
309362306a36Sopenharmony_ci
309462306a36Sopenharmony_cistatic bool _dispc_mgr_size_ok(struct dispc_device *dispc,
309562306a36Sopenharmony_ci			       u16 width, u16 height)
309662306a36Sopenharmony_ci{
309762306a36Sopenharmony_ci	return width <= dispc->feat->mgr_width_max &&
309862306a36Sopenharmony_ci		height <= dispc->feat->mgr_height_max;
309962306a36Sopenharmony_ci}
310062306a36Sopenharmony_ci
310162306a36Sopenharmony_cistatic bool _dispc_lcd_timings_ok(struct dispc_device *dispc,
310262306a36Sopenharmony_ci				  int hsync_len, int hfp, int hbp,
310362306a36Sopenharmony_ci				  int vsw, int vfp, int vbp)
310462306a36Sopenharmony_ci{
310562306a36Sopenharmony_ci	if (hsync_len < 1 || hsync_len > dispc->feat->sw_max ||
310662306a36Sopenharmony_ci	    hfp < 1 || hfp > dispc->feat->hp_max ||
310762306a36Sopenharmony_ci	    hbp < 1 || hbp > dispc->feat->hp_max ||
310862306a36Sopenharmony_ci	    vsw < 1 || vsw > dispc->feat->sw_max ||
310962306a36Sopenharmony_ci	    vfp < 0 || vfp > dispc->feat->vp_max ||
311062306a36Sopenharmony_ci	    vbp < 0 || vbp > dispc->feat->vp_max)
311162306a36Sopenharmony_ci		return false;
311262306a36Sopenharmony_ci	return true;
311362306a36Sopenharmony_ci}
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_cistatic bool _dispc_mgr_pclk_ok(struct dispc_device *dispc,
311662306a36Sopenharmony_ci			       enum omap_channel channel,
311762306a36Sopenharmony_ci			       unsigned long pclk)
311862306a36Sopenharmony_ci{
311962306a36Sopenharmony_ci	if (dss_mgr_is_lcd(channel))
312062306a36Sopenharmony_ci		return pclk <= dispc->feat->max_lcd_pclk;
312162306a36Sopenharmony_ci	else
312262306a36Sopenharmony_ci		return pclk <= dispc->feat->max_tv_pclk;
312362306a36Sopenharmony_ci}
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ciint dispc_mgr_check_timings(struct dispc_device *dispc,
312662306a36Sopenharmony_ci				   enum omap_channel channel,
312762306a36Sopenharmony_ci				   const struct videomode *vm)
312862306a36Sopenharmony_ci{
312962306a36Sopenharmony_ci	if (!_dispc_mgr_size_ok(dispc, vm->hactive, vm->vactive))
313062306a36Sopenharmony_ci		return MODE_BAD;
313162306a36Sopenharmony_ci
313262306a36Sopenharmony_ci	if (!_dispc_mgr_pclk_ok(dispc, channel, vm->pixelclock))
313362306a36Sopenharmony_ci		return MODE_BAD;
313462306a36Sopenharmony_ci
313562306a36Sopenharmony_ci	if (dss_mgr_is_lcd(channel)) {
313662306a36Sopenharmony_ci		/* TODO: OMAP4+ supports interlace for LCD outputs */
313762306a36Sopenharmony_ci		if (vm->flags & DISPLAY_FLAGS_INTERLACED)
313862306a36Sopenharmony_ci			return MODE_BAD;
313962306a36Sopenharmony_ci
314062306a36Sopenharmony_ci		if (!_dispc_lcd_timings_ok(dispc, vm->hsync_len,
314162306a36Sopenharmony_ci				vm->hfront_porch, vm->hback_porch,
314262306a36Sopenharmony_ci				vm->vsync_len, vm->vfront_porch,
314362306a36Sopenharmony_ci				vm->vback_porch))
314462306a36Sopenharmony_ci			return MODE_BAD;
314562306a36Sopenharmony_ci	}
314662306a36Sopenharmony_ci
314762306a36Sopenharmony_ci	return MODE_OK;
314862306a36Sopenharmony_ci}
314962306a36Sopenharmony_ci
315062306a36Sopenharmony_cistatic void _dispc_mgr_set_lcd_timings(struct dispc_device *dispc,
315162306a36Sopenharmony_ci				       enum omap_channel channel,
315262306a36Sopenharmony_ci				       const struct videomode *vm)
315362306a36Sopenharmony_ci{
315462306a36Sopenharmony_ci	u32 timing_h, timing_v, l;
315562306a36Sopenharmony_ci	bool onoff, rf, ipc, vs, hs, de;
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ci	timing_h = FLD_VAL(vm->hsync_len - 1, dispc->feat->sw_start, 0) |
315862306a36Sopenharmony_ci		   FLD_VAL(vm->hfront_porch - 1, dispc->feat->fp_start, 8) |
315962306a36Sopenharmony_ci		   FLD_VAL(vm->hback_porch - 1, dispc->feat->bp_start, 20);
316062306a36Sopenharmony_ci	timing_v = FLD_VAL(vm->vsync_len - 1, dispc->feat->sw_start, 0) |
316162306a36Sopenharmony_ci		   FLD_VAL(vm->vfront_porch, dispc->feat->fp_start, 8) |
316262306a36Sopenharmony_ci		   FLD_VAL(vm->vback_porch, dispc->feat->bp_start, 20);
316362306a36Sopenharmony_ci
316462306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_TIMING_H(channel), timing_h);
316562306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_TIMING_V(channel), timing_v);
316662306a36Sopenharmony_ci
316762306a36Sopenharmony_ci	vs = !!(vm->flags & DISPLAY_FLAGS_VSYNC_LOW);
316862306a36Sopenharmony_ci	hs = !!(vm->flags & DISPLAY_FLAGS_HSYNC_LOW);
316962306a36Sopenharmony_ci	de = !!(vm->flags & DISPLAY_FLAGS_DE_LOW);
317062306a36Sopenharmony_ci	ipc = !!(vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE);
317162306a36Sopenharmony_ci	onoff = true; /* always use the 'rf' setting */
317262306a36Sopenharmony_ci	rf = !!(vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE);
317362306a36Sopenharmony_ci
317462306a36Sopenharmony_ci	l = FLD_VAL(onoff, 17, 17) |
317562306a36Sopenharmony_ci		FLD_VAL(rf, 16, 16) |
317662306a36Sopenharmony_ci		FLD_VAL(de, 15, 15) |
317762306a36Sopenharmony_ci		FLD_VAL(ipc, 14, 14) |
317862306a36Sopenharmony_ci		FLD_VAL(hs, 13, 13) |
317962306a36Sopenharmony_ci		FLD_VAL(vs, 12, 12);
318062306a36Sopenharmony_ci
318162306a36Sopenharmony_ci	/* always set ALIGN bit when available */
318262306a36Sopenharmony_ci	if (dispc->feat->supports_sync_align)
318362306a36Sopenharmony_ci		l |= (1 << 18);
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_POL_FREQ(channel), l);
318662306a36Sopenharmony_ci
318762306a36Sopenharmony_ci	if (dispc->syscon_pol) {
318862306a36Sopenharmony_ci		const int shifts[] = {
318962306a36Sopenharmony_ci			[OMAP_DSS_CHANNEL_LCD] = 0,
319062306a36Sopenharmony_ci			[OMAP_DSS_CHANNEL_LCD2] = 1,
319162306a36Sopenharmony_ci			[OMAP_DSS_CHANNEL_LCD3] = 2,
319262306a36Sopenharmony_ci		};
319362306a36Sopenharmony_ci
319462306a36Sopenharmony_ci		u32 mask, val;
319562306a36Sopenharmony_ci
319662306a36Sopenharmony_ci		mask = (1 << 0) | (1 << 3) | (1 << 6);
319762306a36Sopenharmony_ci		val = (rf << 0) | (ipc << 3) | (onoff << 6);
319862306a36Sopenharmony_ci
319962306a36Sopenharmony_ci		mask <<= 16 + shifts[channel];
320062306a36Sopenharmony_ci		val <<= 16 + shifts[channel];
320162306a36Sopenharmony_ci
320262306a36Sopenharmony_ci		regmap_update_bits(dispc->syscon_pol, dispc->syscon_pol_offset,
320362306a36Sopenharmony_ci				   mask, val);
320462306a36Sopenharmony_ci	}
320562306a36Sopenharmony_ci}
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_cistatic int vm_flag_to_int(enum display_flags flags, enum display_flags high,
320862306a36Sopenharmony_ci	enum display_flags low)
320962306a36Sopenharmony_ci{
321062306a36Sopenharmony_ci	if (flags & high)
321162306a36Sopenharmony_ci		return 1;
321262306a36Sopenharmony_ci	if (flags & low)
321362306a36Sopenharmony_ci		return -1;
321462306a36Sopenharmony_ci	return 0;
321562306a36Sopenharmony_ci}
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci/* change name to mode? */
321862306a36Sopenharmony_civoid dispc_mgr_set_timings(struct dispc_device *dispc,
321962306a36Sopenharmony_ci				  enum omap_channel channel,
322062306a36Sopenharmony_ci				  const struct videomode *vm)
322162306a36Sopenharmony_ci{
322262306a36Sopenharmony_ci	unsigned int xtot, ytot;
322362306a36Sopenharmony_ci	unsigned long ht, vt;
322462306a36Sopenharmony_ci	struct videomode t = *vm;
322562306a36Sopenharmony_ci
322662306a36Sopenharmony_ci	DSSDBG("channel %d xres %u yres %u\n", channel, t.hactive, t.vactive);
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_ci	if (dispc_mgr_check_timings(dispc, channel, &t)) {
322962306a36Sopenharmony_ci		BUG();
323062306a36Sopenharmony_ci		return;
323162306a36Sopenharmony_ci	}
323262306a36Sopenharmony_ci
323362306a36Sopenharmony_ci	if (dss_mgr_is_lcd(channel)) {
323462306a36Sopenharmony_ci		_dispc_mgr_set_lcd_timings(dispc, channel, &t);
323562306a36Sopenharmony_ci
323662306a36Sopenharmony_ci		xtot = t.hactive + t.hfront_porch + t.hsync_len + t.hback_porch;
323762306a36Sopenharmony_ci		ytot = t.vactive + t.vfront_porch + t.vsync_len + t.vback_porch;
323862306a36Sopenharmony_ci
323962306a36Sopenharmony_ci		ht = vm->pixelclock / xtot;
324062306a36Sopenharmony_ci		vt = vm->pixelclock / xtot / ytot;
324162306a36Sopenharmony_ci
324262306a36Sopenharmony_ci		DSSDBG("pck %lu\n", vm->pixelclock);
324362306a36Sopenharmony_ci		DSSDBG("hsync_len %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
324462306a36Sopenharmony_ci			t.hsync_len, t.hfront_porch, t.hback_porch,
324562306a36Sopenharmony_ci			t.vsync_len, t.vfront_porch, t.vback_porch);
324662306a36Sopenharmony_ci		DSSDBG("vsync_level %d hsync_level %d data_pclk_edge %d de_level %d sync_pclk_edge %d\n",
324762306a36Sopenharmony_ci			vm_flag_to_int(t.flags, DISPLAY_FLAGS_VSYNC_HIGH, DISPLAY_FLAGS_VSYNC_LOW),
324862306a36Sopenharmony_ci			vm_flag_to_int(t.flags, DISPLAY_FLAGS_HSYNC_HIGH, DISPLAY_FLAGS_HSYNC_LOW),
324962306a36Sopenharmony_ci			vm_flag_to_int(t.flags, DISPLAY_FLAGS_PIXDATA_POSEDGE, DISPLAY_FLAGS_PIXDATA_NEGEDGE),
325062306a36Sopenharmony_ci			vm_flag_to_int(t.flags, DISPLAY_FLAGS_DE_HIGH, DISPLAY_FLAGS_DE_LOW),
325162306a36Sopenharmony_ci			vm_flag_to_int(t.flags, DISPLAY_FLAGS_SYNC_POSEDGE, DISPLAY_FLAGS_SYNC_NEGEDGE));
325262306a36Sopenharmony_ci
325362306a36Sopenharmony_ci		DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
325462306a36Sopenharmony_ci	} else {
325562306a36Sopenharmony_ci		if (t.flags & DISPLAY_FLAGS_INTERLACED)
325662306a36Sopenharmony_ci			t.vactive /= 2;
325762306a36Sopenharmony_ci
325862306a36Sopenharmony_ci		if (dispc->feat->supports_double_pixel)
325962306a36Sopenharmony_ci			REG_FLD_MOD(dispc, DISPC_CONTROL,
326062306a36Sopenharmony_ci				    !!(t.flags & DISPLAY_FLAGS_DOUBLECLK),
326162306a36Sopenharmony_ci				    19, 17);
326262306a36Sopenharmony_ci	}
326362306a36Sopenharmony_ci
326462306a36Sopenharmony_ci	dispc_mgr_set_size(dispc, channel, t.hactive, t.vactive);
326562306a36Sopenharmony_ci}
326662306a36Sopenharmony_ci
326762306a36Sopenharmony_cistatic void dispc_mgr_set_lcd_divisor(struct dispc_device *dispc,
326862306a36Sopenharmony_ci				      enum omap_channel channel, u16 lck_div,
326962306a36Sopenharmony_ci				      u16 pck_div)
327062306a36Sopenharmony_ci{
327162306a36Sopenharmony_ci	BUG_ON(lck_div < 1);
327262306a36Sopenharmony_ci	BUG_ON(pck_div < 1);
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_DIVISORo(channel),
327562306a36Sopenharmony_ci			FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
327662306a36Sopenharmony_ci
327762306a36Sopenharmony_ci	if (!dispc_has_feature(dispc, FEAT_CORE_CLK_DIV) &&
327862306a36Sopenharmony_ci			channel == OMAP_DSS_CHANNEL_LCD)
327962306a36Sopenharmony_ci		dispc->core_clk_rate = dispc_fclk_rate(dispc) / lck_div;
328062306a36Sopenharmony_ci}
328162306a36Sopenharmony_ci
328262306a36Sopenharmony_cistatic void dispc_mgr_get_lcd_divisor(struct dispc_device *dispc,
328362306a36Sopenharmony_ci				      enum omap_channel channel, int *lck_div,
328462306a36Sopenharmony_ci				      int *pck_div)
328562306a36Sopenharmony_ci{
328662306a36Sopenharmony_ci	u32 l;
328762306a36Sopenharmony_ci	l = dispc_read_reg(dispc, DISPC_DIVISORo(channel));
328862306a36Sopenharmony_ci	*lck_div = FLD_GET(l, 23, 16);
328962306a36Sopenharmony_ci	*pck_div = FLD_GET(l, 7, 0);
329062306a36Sopenharmony_ci}
329162306a36Sopenharmony_ci
329262306a36Sopenharmony_cistatic unsigned long dispc_fclk_rate(struct dispc_device *dispc)
329362306a36Sopenharmony_ci{
329462306a36Sopenharmony_ci	unsigned long r;
329562306a36Sopenharmony_ci	enum dss_clk_source src;
329662306a36Sopenharmony_ci
329762306a36Sopenharmony_ci	src = dss_get_dispc_clk_source(dispc->dss);
329862306a36Sopenharmony_ci
329962306a36Sopenharmony_ci	if (src == DSS_CLK_SRC_FCK) {
330062306a36Sopenharmony_ci		r = dss_get_dispc_clk_rate(dispc->dss);
330162306a36Sopenharmony_ci	} else {
330262306a36Sopenharmony_ci		struct dss_pll *pll;
330362306a36Sopenharmony_ci		unsigned int clkout_idx;
330462306a36Sopenharmony_ci
330562306a36Sopenharmony_ci		pll = dss_pll_find_by_src(dispc->dss, src);
330662306a36Sopenharmony_ci		clkout_idx = dss_pll_get_clkout_idx_for_src(src);
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_ci		r = pll->cinfo.clkout[clkout_idx];
330962306a36Sopenharmony_ci	}
331062306a36Sopenharmony_ci
331162306a36Sopenharmony_ci	return r;
331262306a36Sopenharmony_ci}
331362306a36Sopenharmony_ci
331462306a36Sopenharmony_cistatic unsigned long dispc_mgr_lclk_rate(struct dispc_device *dispc,
331562306a36Sopenharmony_ci					 enum omap_channel channel)
331662306a36Sopenharmony_ci{
331762306a36Sopenharmony_ci	int lcd;
331862306a36Sopenharmony_ci	unsigned long r;
331962306a36Sopenharmony_ci	enum dss_clk_source src;
332062306a36Sopenharmony_ci
332162306a36Sopenharmony_ci	/* for TV, LCLK rate is the FCLK rate */
332262306a36Sopenharmony_ci	if (!dss_mgr_is_lcd(channel))
332362306a36Sopenharmony_ci		return dispc_fclk_rate(dispc);
332462306a36Sopenharmony_ci
332562306a36Sopenharmony_ci	src = dss_get_lcd_clk_source(dispc->dss, channel);
332662306a36Sopenharmony_ci
332762306a36Sopenharmony_ci	if (src == DSS_CLK_SRC_FCK) {
332862306a36Sopenharmony_ci		r = dss_get_dispc_clk_rate(dispc->dss);
332962306a36Sopenharmony_ci	} else {
333062306a36Sopenharmony_ci		struct dss_pll *pll;
333162306a36Sopenharmony_ci		unsigned int clkout_idx;
333262306a36Sopenharmony_ci
333362306a36Sopenharmony_ci		pll = dss_pll_find_by_src(dispc->dss, src);
333462306a36Sopenharmony_ci		clkout_idx = dss_pll_get_clkout_idx_for_src(src);
333562306a36Sopenharmony_ci
333662306a36Sopenharmony_ci		r = pll->cinfo.clkout[clkout_idx];
333762306a36Sopenharmony_ci	}
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci	lcd = REG_GET(dispc, DISPC_DIVISORo(channel), 23, 16);
334062306a36Sopenharmony_ci
334162306a36Sopenharmony_ci	return r / lcd;
334262306a36Sopenharmony_ci}
334362306a36Sopenharmony_ci
334462306a36Sopenharmony_cistatic unsigned long dispc_mgr_pclk_rate(struct dispc_device *dispc,
334562306a36Sopenharmony_ci					 enum omap_channel channel)
334662306a36Sopenharmony_ci{
334762306a36Sopenharmony_ci	unsigned long r;
334862306a36Sopenharmony_ci
334962306a36Sopenharmony_ci	if (dss_mgr_is_lcd(channel)) {
335062306a36Sopenharmony_ci		int pcd;
335162306a36Sopenharmony_ci		u32 l;
335262306a36Sopenharmony_ci
335362306a36Sopenharmony_ci		l = dispc_read_reg(dispc, DISPC_DIVISORo(channel));
335462306a36Sopenharmony_ci
335562306a36Sopenharmony_ci		pcd = FLD_GET(l, 7, 0);
335662306a36Sopenharmony_ci
335762306a36Sopenharmony_ci		r = dispc_mgr_lclk_rate(dispc, channel);
335862306a36Sopenharmony_ci
335962306a36Sopenharmony_ci		return r / pcd;
336062306a36Sopenharmony_ci	} else {
336162306a36Sopenharmony_ci		return dispc->tv_pclk_rate;
336262306a36Sopenharmony_ci	}
336362306a36Sopenharmony_ci}
336462306a36Sopenharmony_ci
336562306a36Sopenharmony_civoid dispc_set_tv_pclk(struct dispc_device *dispc, unsigned long pclk)
336662306a36Sopenharmony_ci{
336762306a36Sopenharmony_ci	dispc->tv_pclk_rate = pclk;
336862306a36Sopenharmony_ci}
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_cistatic unsigned long dispc_core_clk_rate(struct dispc_device *dispc)
337162306a36Sopenharmony_ci{
337262306a36Sopenharmony_ci	return dispc->core_clk_rate;
337362306a36Sopenharmony_ci}
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_cistatic unsigned long dispc_plane_pclk_rate(struct dispc_device *dispc,
337662306a36Sopenharmony_ci					   enum omap_plane_id plane)
337762306a36Sopenharmony_ci{
337862306a36Sopenharmony_ci	enum omap_channel channel;
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_ci	if (plane == OMAP_DSS_WB)
338162306a36Sopenharmony_ci		return 0;
338262306a36Sopenharmony_ci
338362306a36Sopenharmony_ci	channel = dispc_ovl_get_channel_out(dispc, plane);
338462306a36Sopenharmony_ci
338562306a36Sopenharmony_ci	return dispc_mgr_pclk_rate(dispc, channel);
338662306a36Sopenharmony_ci}
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_cistatic unsigned long dispc_plane_lclk_rate(struct dispc_device *dispc,
338962306a36Sopenharmony_ci					   enum omap_plane_id plane)
339062306a36Sopenharmony_ci{
339162306a36Sopenharmony_ci	enum omap_channel channel;
339262306a36Sopenharmony_ci
339362306a36Sopenharmony_ci	if (plane == OMAP_DSS_WB)
339462306a36Sopenharmony_ci		return 0;
339562306a36Sopenharmony_ci
339662306a36Sopenharmony_ci	channel	= dispc_ovl_get_channel_out(dispc, plane);
339762306a36Sopenharmony_ci
339862306a36Sopenharmony_ci	return dispc_mgr_lclk_rate(dispc, channel);
339962306a36Sopenharmony_ci}
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_cistatic void dispc_dump_clocks_channel(struct dispc_device *dispc,
340262306a36Sopenharmony_ci				      struct seq_file *s,
340362306a36Sopenharmony_ci				      enum omap_channel channel)
340462306a36Sopenharmony_ci{
340562306a36Sopenharmony_ci	int lcd, pcd;
340662306a36Sopenharmony_ci	enum dss_clk_source lcd_clk_src;
340762306a36Sopenharmony_ci
340862306a36Sopenharmony_ci	seq_printf(s, "- %s -\n", mgr_desc[channel].name);
340962306a36Sopenharmony_ci
341062306a36Sopenharmony_ci	lcd_clk_src = dss_get_lcd_clk_source(dispc->dss, channel);
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_ci	seq_printf(s, "%s clk source = %s\n", mgr_desc[channel].name,
341362306a36Sopenharmony_ci		dss_get_clk_source_name(lcd_clk_src));
341462306a36Sopenharmony_ci
341562306a36Sopenharmony_ci	dispc_mgr_get_lcd_divisor(dispc, channel, &lcd, &pcd);
341662306a36Sopenharmony_ci
341762306a36Sopenharmony_ci	seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
341862306a36Sopenharmony_ci		dispc_mgr_lclk_rate(dispc, channel), lcd);
341962306a36Sopenharmony_ci	seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
342062306a36Sopenharmony_ci		dispc_mgr_pclk_rate(dispc, channel), pcd);
342162306a36Sopenharmony_ci}
342262306a36Sopenharmony_ci
342362306a36Sopenharmony_civoid dispc_dump_clocks(struct dispc_device *dispc, struct seq_file *s)
342462306a36Sopenharmony_ci{
342562306a36Sopenharmony_ci	enum dss_clk_source dispc_clk_src;
342662306a36Sopenharmony_ci	int lcd;
342762306a36Sopenharmony_ci	u32 l;
342862306a36Sopenharmony_ci
342962306a36Sopenharmony_ci	if (dispc_runtime_get(dispc))
343062306a36Sopenharmony_ci		return;
343162306a36Sopenharmony_ci
343262306a36Sopenharmony_ci	seq_printf(s, "- DISPC -\n");
343362306a36Sopenharmony_ci
343462306a36Sopenharmony_ci	dispc_clk_src = dss_get_dispc_clk_source(dispc->dss);
343562306a36Sopenharmony_ci	seq_printf(s, "dispc fclk source = %s\n",
343662306a36Sopenharmony_ci			dss_get_clk_source_name(dispc_clk_src));
343762306a36Sopenharmony_ci
343862306a36Sopenharmony_ci	seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate(dispc));
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) {
344162306a36Sopenharmony_ci		seq_printf(s, "- DISPC-CORE-CLK -\n");
344262306a36Sopenharmony_ci		l = dispc_read_reg(dispc, DISPC_DIVISOR);
344362306a36Sopenharmony_ci		lcd = FLD_GET(l, 23, 16);
344462306a36Sopenharmony_ci
344562306a36Sopenharmony_ci		seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
344662306a36Sopenharmony_ci				(dispc_fclk_rate(dispc)/lcd), lcd);
344762306a36Sopenharmony_ci	}
344862306a36Sopenharmony_ci
344962306a36Sopenharmony_ci	dispc_dump_clocks_channel(dispc, s, OMAP_DSS_CHANNEL_LCD);
345062306a36Sopenharmony_ci
345162306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_MGR_LCD2))
345262306a36Sopenharmony_ci		dispc_dump_clocks_channel(dispc, s, OMAP_DSS_CHANNEL_LCD2);
345362306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_MGR_LCD3))
345462306a36Sopenharmony_ci		dispc_dump_clocks_channel(dispc, s, OMAP_DSS_CHANNEL_LCD3);
345562306a36Sopenharmony_ci
345662306a36Sopenharmony_ci	dispc_runtime_put(dispc);
345762306a36Sopenharmony_ci}
345862306a36Sopenharmony_ci
345962306a36Sopenharmony_cistatic int dispc_dump_regs(struct seq_file *s, void *p)
346062306a36Sopenharmony_ci{
346162306a36Sopenharmony_ci	struct dispc_device *dispc = s->private;
346262306a36Sopenharmony_ci	int i, j;
346362306a36Sopenharmony_ci	const char *mgr_names[] = {
346462306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_LCD]		= "LCD",
346562306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_DIGIT]	= "TV",
346662306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_LCD2]		= "LCD2",
346762306a36Sopenharmony_ci		[OMAP_DSS_CHANNEL_LCD3]		= "LCD3",
346862306a36Sopenharmony_ci	};
346962306a36Sopenharmony_ci	const char *ovl_names[] = {
347062306a36Sopenharmony_ci		[OMAP_DSS_GFX]		= "GFX",
347162306a36Sopenharmony_ci		[OMAP_DSS_VIDEO1]	= "VID1",
347262306a36Sopenharmony_ci		[OMAP_DSS_VIDEO2]	= "VID2",
347362306a36Sopenharmony_ci		[OMAP_DSS_VIDEO3]	= "VID3",
347462306a36Sopenharmony_ci		[OMAP_DSS_WB]		= "WB",
347562306a36Sopenharmony_ci	};
347662306a36Sopenharmony_ci	const char **p_names;
347762306a36Sopenharmony_ci
347862306a36Sopenharmony_ci#define DUMPREG(dispc, r) \
347962306a36Sopenharmony_ci	seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(dispc, r))
348062306a36Sopenharmony_ci
348162306a36Sopenharmony_ci	if (dispc_runtime_get(dispc))
348262306a36Sopenharmony_ci		return 0;
348362306a36Sopenharmony_ci
348462306a36Sopenharmony_ci	/* DISPC common registers */
348562306a36Sopenharmony_ci	DUMPREG(dispc, DISPC_REVISION);
348662306a36Sopenharmony_ci	DUMPREG(dispc, DISPC_SYSCONFIG);
348762306a36Sopenharmony_ci	DUMPREG(dispc, DISPC_SYSSTATUS);
348862306a36Sopenharmony_ci	DUMPREG(dispc, DISPC_IRQSTATUS);
348962306a36Sopenharmony_ci	DUMPREG(dispc, DISPC_IRQENABLE);
349062306a36Sopenharmony_ci	DUMPREG(dispc, DISPC_CONTROL);
349162306a36Sopenharmony_ci	DUMPREG(dispc, DISPC_CONFIG);
349262306a36Sopenharmony_ci	DUMPREG(dispc, DISPC_CAPABLE);
349362306a36Sopenharmony_ci	DUMPREG(dispc, DISPC_LINE_STATUS);
349462306a36Sopenharmony_ci	DUMPREG(dispc, DISPC_LINE_NUMBER);
349562306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER) ||
349662306a36Sopenharmony_ci			dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER))
349762306a36Sopenharmony_ci		DUMPREG(dispc, DISPC_GLOBAL_ALPHA);
349862306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) {
349962306a36Sopenharmony_ci		DUMPREG(dispc, DISPC_CONTROL2);
350062306a36Sopenharmony_ci		DUMPREG(dispc, DISPC_CONFIG2);
350162306a36Sopenharmony_ci	}
350262306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) {
350362306a36Sopenharmony_ci		DUMPREG(dispc, DISPC_CONTROL3);
350462306a36Sopenharmony_ci		DUMPREG(dispc, DISPC_CONFIG3);
350562306a36Sopenharmony_ci	}
350662306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_MFLAG))
350762306a36Sopenharmony_ci		DUMPREG(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE);
350862306a36Sopenharmony_ci
350962306a36Sopenharmony_ci#undef DUMPREG
351062306a36Sopenharmony_ci
351162306a36Sopenharmony_ci#define DISPC_REG(i, name) name(i)
351262306a36Sopenharmony_ci#define DUMPREG(dispc, i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \
351362306a36Sopenharmony_ci	(int)(48 - strlen(#r) - strlen(p_names[i])), " ", \
351462306a36Sopenharmony_ci	dispc_read_reg(dispc, DISPC_REG(i, r)))
351562306a36Sopenharmony_ci
351662306a36Sopenharmony_ci	p_names = mgr_names;
351762306a36Sopenharmony_ci
351862306a36Sopenharmony_ci	/* DISPC channel specific registers */
351962306a36Sopenharmony_ci	for (i = 0; i < dispc_get_num_mgrs(dispc); i++) {
352062306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_DEFAULT_COLOR);
352162306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_TRANS_COLOR);
352262306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_SIZE_MGR);
352362306a36Sopenharmony_ci
352462306a36Sopenharmony_ci		if (i == OMAP_DSS_CHANNEL_DIGIT)
352562306a36Sopenharmony_ci			continue;
352662306a36Sopenharmony_ci
352762306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_TIMING_H);
352862306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_TIMING_V);
352962306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_POL_FREQ);
353062306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_DIVISORo);
353162306a36Sopenharmony_ci
353262306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_DATA_CYCLE1);
353362306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_DATA_CYCLE2);
353462306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_DATA_CYCLE3);
353562306a36Sopenharmony_ci
353662306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_CPR)) {
353762306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_CPR_COEF_R);
353862306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_CPR_COEF_G);
353962306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_CPR_COEF_B);
354062306a36Sopenharmony_ci		}
354162306a36Sopenharmony_ci	}
354262306a36Sopenharmony_ci
354362306a36Sopenharmony_ci	p_names = ovl_names;
354462306a36Sopenharmony_ci
354562306a36Sopenharmony_ci	for (i = 0; i < dispc_get_num_ovls(dispc); i++) {
354662306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_BA0);
354762306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_BA1);
354862306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_POSITION);
354962306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_SIZE);
355062306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES);
355162306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_FIFO_THRESHOLD);
355262306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_FIFO_SIZE_STATUS);
355362306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_ROW_INC);
355462306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_PIXEL_INC);
355562306a36Sopenharmony_ci
355662306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_PRELOAD))
355762306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_PRELOAD);
355862306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_MFLAG))
355962306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_MFLAG_THRESHOLD);
356062306a36Sopenharmony_ci
356162306a36Sopenharmony_ci		if (i == OMAP_DSS_GFX) {
356262306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_WINDOW_SKIP);
356362306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_TABLE_BA);
356462306a36Sopenharmony_ci			continue;
356562306a36Sopenharmony_ci		}
356662306a36Sopenharmony_ci
356762306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_FIR);
356862306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_PICTURE_SIZE);
356962306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_ACCU0);
357062306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_ACCU1);
357162306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) {
357262306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_BA0_UV);
357362306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_BA1_UV);
357462306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_FIR2);
357562306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_ACCU2_0);
357662306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_ACCU2_1);
357762306a36Sopenharmony_ci		}
357862306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_ATTR2))
357962306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES2);
358062306a36Sopenharmony_ci	}
358162306a36Sopenharmony_ci
358262306a36Sopenharmony_ci	if (dispc->feat->has_writeback) {
358362306a36Sopenharmony_ci		i = OMAP_DSS_WB;
358462306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_BA0);
358562306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_BA1);
358662306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_SIZE);
358762306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES);
358862306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_FIFO_THRESHOLD);
358962306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_FIFO_SIZE_STATUS);
359062306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_ROW_INC);
359162306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_PIXEL_INC);
359262306a36Sopenharmony_ci
359362306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_MFLAG))
359462306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_MFLAG_THRESHOLD);
359562306a36Sopenharmony_ci
359662306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_FIR);
359762306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_PICTURE_SIZE);
359862306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_ACCU0);
359962306a36Sopenharmony_ci		DUMPREG(dispc, i, DISPC_OVL_ACCU1);
360062306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) {
360162306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_BA0_UV);
360262306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_BA1_UV);
360362306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_FIR2);
360462306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_ACCU2_0);
360562306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_ACCU2_1);
360662306a36Sopenharmony_ci		}
360762306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_ATTR2))
360862306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES2);
360962306a36Sopenharmony_ci	}
361062306a36Sopenharmony_ci
361162306a36Sopenharmony_ci#undef DISPC_REG
361262306a36Sopenharmony_ci#undef DUMPREG
361362306a36Sopenharmony_ci
361462306a36Sopenharmony_ci#define DISPC_REG(plane, name, i) name(plane, i)
361562306a36Sopenharmony_ci#define DUMPREG(dispc, plane, name, i) \
361662306a36Sopenharmony_ci	seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \
361762306a36Sopenharmony_ci	(int)(46 - strlen(#name) - strlen(p_names[plane])), " ", \
361862306a36Sopenharmony_ci	dispc_read_reg(dispc, DISPC_REG(plane, name, i)))
361962306a36Sopenharmony_ci
362062306a36Sopenharmony_ci	/* Video pipeline coefficient registers */
362162306a36Sopenharmony_ci
362262306a36Sopenharmony_ci	/* start from OMAP_DSS_VIDEO1 */
362362306a36Sopenharmony_ci	for (i = 1; i < dispc_get_num_ovls(dispc); i++) {
362462306a36Sopenharmony_ci		for (j = 0; j < 8; j++)
362562306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_H, j);
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ci		for (j = 0; j < 8; j++)
362862306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_HV, j);
362962306a36Sopenharmony_ci
363062306a36Sopenharmony_ci		for (j = 0; j < 5; j++)
363162306a36Sopenharmony_ci			DUMPREG(dispc, i, DISPC_OVL_CONV_COEF, j);
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_FIR_COEF_V)) {
363462306a36Sopenharmony_ci			for (j = 0; j < 8; j++)
363562306a36Sopenharmony_ci				DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_V, j);
363662306a36Sopenharmony_ci		}
363762306a36Sopenharmony_ci
363862306a36Sopenharmony_ci		if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) {
363962306a36Sopenharmony_ci			for (j = 0; j < 8; j++)
364062306a36Sopenharmony_ci				DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_H2, j);
364162306a36Sopenharmony_ci
364262306a36Sopenharmony_ci			for (j = 0; j < 8; j++)
364362306a36Sopenharmony_ci				DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_HV2, j);
364462306a36Sopenharmony_ci
364562306a36Sopenharmony_ci			for (j = 0; j < 8; j++)
364662306a36Sopenharmony_ci				DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_V2, j);
364762306a36Sopenharmony_ci		}
364862306a36Sopenharmony_ci	}
364962306a36Sopenharmony_ci
365062306a36Sopenharmony_ci	dispc_runtime_put(dispc);
365162306a36Sopenharmony_ci
365262306a36Sopenharmony_ci#undef DISPC_REG
365362306a36Sopenharmony_ci#undef DUMPREG
365462306a36Sopenharmony_ci
365562306a36Sopenharmony_ci	return 0;
365662306a36Sopenharmony_ci}
365762306a36Sopenharmony_ci
365862306a36Sopenharmony_ci/* calculate clock rates using dividers in cinfo */
365962306a36Sopenharmony_ciint dispc_calc_clock_rates(struct dispc_device *dispc,
366062306a36Sopenharmony_ci			   unsigned long dispc_fclk_rate,
366162306a36Sopenharmony_ci			   struct dispc_clock_info *cinfo)
366262306a36Sopenharmony_ci{
366362306a36Sopenharmony_ci	if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
366462306a36Sopenharmony_ci		return -EINVAL;
366562306a36Sopenharmony_ci	if (cinfo->pck_div < 1 || cinfo->pck_div > 255)
366662306a36Sopenharmony_ci		return -EINVAL;
366762306a36Sopenharmony_ci
366862306a36Sopenharmony_ci	cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
366962306a36Sopenharmony_ci	cinfo->pck = cinfo->lck / cinfo->pck_div;
367062306a36Sopenharmony_ci
367162306a36Sopenharmony_ci	return 0;
367262306a36Sopenharmony_ci}
367362306a36Sopenharmony_ci
367462306a36Sopenharmony_cibool dispc_div_calc(struct dispc_device *dispc, unsigned long dispc_freq,
367562306a36Sopenharmony_ci		    unsigned long pck_min, unsigned long pck_max,
367662306a36Sopenharmony_ci		    dispc_div_calc_func func, void *data)
367762306a36Sopenharmony_ci{
367862306a36Sopenharmony_ci	int lckd, lckd_start, lckd_stop;
367962306a36Sopenharmony_ci	int pckd, pckd_start, pckd_stop;
368062306a36Sopenharmony_ci	unsigned long pck, lck;
368162306a36Sopenharmony_ci	unsigned long lck_max;
368262306a36Sopenharmony_ci	unsigned long pckd_hw_min, pckd_hw_max;
368362306a36Sopenharmony_ci	unsigned int min_fck_per_pck;
368462306a36Sopenharmony_ci	unsigned long fck;
368562306a36Sopenharmony_ci
368662306a36Sopenharmony_ci#ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK
368762306a36Sopenharmony_ci	min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
368862306a36Sopenharmony_ci#else
368962306a36Sopenharmony_ci	min_fck_per_pck = 0;
369062306a36Sopenharmony_ci#endif
369162306a36Sopenharmony_ci
369262306a36Sopenharmony_ci	pckd_hw_min = dispc->feat->min_pcd;
369362306a36Sopenharmony_ci	pckd_hw_max = 255;
369462306a36Sopenharmony_ci
369562306a36Sopenharmony_ci	lck_max = dss_get_max_fck_rate(dispc->dss);
369662306a36Sopenharmony_ci
369762306a36Sopenharmony_ci	pck_min = pck_min ? pck_min : 1;
369862306a36Sopenharmony_ci	pck_max = pck_max ? pck_max : ULONG_MAX;
369962306a36Sopenharmony_ci
370062306a36Sopenharmony_ci	lckd_start = max(DIV_ROUND_UP(dispc_freq, lck_max), 1ul);
370162306a36Sopenharmony_ci	lckd_stop = min(dispc_freq / pck_min, 255ul);
370262306a36Sopenharmony_ci
370362306a36Sopenharmony_ci	for (lckd = lckd_start; lckd <= lckd_stop; ++lckd) {
370462306a36Sopenharmony_ci		lck = dispc_freq / lckd;
370562306a36Sopenharmony_ci
370662306a36Sopenharmony_ci		pckd_start = max(DIV_ROUND_UP(lck, pck_max), pckd_hw_min);
370762306a36Sopenharmony_ci		pckd_stop = min(lck / pck_min, pckd_hw_max);
370862306a36Sopenharmony_ci
370962306a36Sopenharmony_ci		for (pckd = pckd_start; pckd <= pckd_stop; ++pckd) {
371062306a36Sopenharmony_ci			pck = lck / pckd;
371162306a36Sopenharmony_ci
371262306a36Sopenharmony_ci			/*
371362306a36Sopenharmony_ci			 * For OMAP2/3 the DISPC fclk is the same as LCD's logic
371462306a36Sopenharmony_ci			 * clock, which means we're configuring DISPC fclk here
371562306a36Sopenharmony_ci			 * also. Thus we need to use the calculated lck. For
371662306a36Sopenharmony_ci			 * OMAP4+ the DISPC fclk is a separate clock.
371762306a36Sopenharmony_ci			 */
371862306a36Sopenharmony_ci			if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV))
371962306a36Sopenharmony_ci				fck = dispc_core_clk_rate(dispc);
372062306a36Sopenharmony_ci			else
372162306a36Sopenharmony_ci				fck = lck;
372262306a36Sopenharmony_ci
372362306a36Sopenharmony_ci			if (fck < pck * min_fck_per_pck)
372462306a36Sopenharmony_ci				continue;
372562306a36Sopenharmony_ci
372662306a36Sopenharmony_ci			if (func(lckd, pckd, lck, pck, data))
372762306a36Sopenharmony_ci				return true;
372862306a36Sopenharmony_ci		}
372962306a36Sopenharmony_ci	}
373062306a36Sopenharmony_ci
373162306a36Sopenharmony_ci	return false;
373262306a36Sopenharmony_ci}
373362306a36Sopenharmony_ci
373462306a36Sopenharmony_civoid dispc_mgr_set_clock_div(struct dispc_device *dispc,
373562306a36Sopenharmony_ci			     enum omap_channel channel,
373662306a36Sopenharmony_ci			     const struct dispc_clock_info *cinfo)
373762306a36Sopenharmony_ci{
373862306a36Sopenharmony_ci	DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
373962306a36Sopenharmony_ci	DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
374062306a36Sopenharmony_ci
374162306a36Sopenharmony_ci	dispc_mgr_set_lcd_divisor(dispc, channel, cinfo->lck_div,
374262306a36Sopenharmony_ci				  cinfo->pck_div);
374362306a36Sopenharmony_ci}
374462306a36Sopenharmony_ci
374562306a36Sopenharmony_ciint dispc_mgr_get_clock_div(struct dispc_device *dispc,
374662306a36Sopenharmony_ci			    enum omap_channel channel,
374762306a36Sopenharmony_ci			    struct dispc_clock_info *cinfo)
374862306a36Sopenharmony_ci{
374962306a36Sopenharmony_ci	unsigned long fck;
375062306a36Sopenharmony_ci
375162306a36Sopenharmony_ci	fck = dispc_fclk_rate(dispc);
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_ci	cinfo->lck_div = REG_GET(dispc, DISPC_DIVISORo(channel), 23, 16);
375462306a36Sopenharmony_ci	cinfo->pck_div = REG_GET(dispc, DISPC_DIVISORo(channel), 7, 0);
375562306a36Sopenharmony_ci
375662306a36Sopenharmony_ci	cinfo->lck = fck / cinfo->lck_div;
375762306a36Sopenharmony_ci	cinfo->pck = cinfo->lck / cinfo->pck_div;
375862306a36Sopenharmony_ci
375962306a36Sopenharmony_ci	return 0;
376062306a36Sopenharmony_ci}
376162306a36Sopenharmony_ci
376262306a36Sopenharmony_ciu32 dispc_read_irqstatus(struct dispc_device *dispc)
376362306a36Sopenharmony_ci{
376462306a36Sopenharmony_ci	return dispc_read_reg(dispc, DISPC_IRQSTATUS);
376562306a36Sopenharmony_ci}
376662306a36Sopenharmony_ci
376762306a36Sopenharmony_civoid dispc_clear_irqstatus(struct dispc_device *dispc, u32 mask)
376862306a36Sopenharmony_ci{
376962306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_IRQSTATUS, mask);
377062306a36Sopenharmony_ci}
377162306a36Sopenharmony_ci
377262306a36Sopenharmony_civoid dispc_write_irqenable(struct dispc_device *dispc, u32 mask)
377362306a36Sopenharmony_ci{
377462306a36Sopenharmony_ci	u32 old_mask = dispc_read_reg(dispc, DISPC_IRQENABLE);
377562306a36Sopenharmony_ci
377662306a36Sopenharmony_ci	/* clear the irqstatus for newly enabled irqs */
377762306a36Sopenharmony_ci	dispc_clear_irqstatus(dispc, (mask ^ old_mask) & mask);
377862306a36Sopenharmony_ci
377962306a36Sopenharmony_ci	dispc_write_reg(dispc, DISPC_IRQENABLE, mask);
378062306a36Sopenharmony_ci
378162306a36Sopenharmony_ci	/* flush posted write */
378262306a36Sopenharmony_ci	dispc_read_reg(dispc, DISPC_IRQENABLE);
378362306a36Sopenharmony_ci}
378462306a36Sopenharmony_ci
378562306a36Sopenharmony_civoid dispc_enable_sidle(struct dispc_device *dispc)
378662306a36Sopenharmony_ci{
378762306a36Sopenharmony_ci	/* SIDLEMODE: smart idle */
378862306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_SYSCONFIG, 2, 4, 3);
378962306a36Sopenharmony_ci}
379062306a36Sopenharmony_ci
379162306a36Sopenharmony_civoid dispc_disable_sidle(struct dispc_device *dispc)
379262306a36Sopenharmony_ci{
379362306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_SYSCONFIG, 1, 4, 3);	/* SIDLEMODE: no idle */
379462306a36Sopenharmony_ci}
379562306a36Sopenharmony_ci
379662306a36Sopenharmony_ciu32 dispc_mgr_gamma_size(struct dispc_device *dispc,
379762306a36Sopenharmony_ci				enum omap_channel channel)
379862306a36Sopenharmony_ci{
379962306a36Sopenharmony_ci	const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
380062306a36Sopenharmony_ci
380162306a36Sopenharmony_ci	if (!dispc->feat->has_gamma_table)
380262306a36Sopenharmony_ci		return 0;
380362306a36Sopenharmony_ci
380462306a36Sopenharmony_ci	return gdesc->len;
380562306a36Sopenharmony_ci}
380662306a36Sopenharmony_ci
380762306a36Sopenharmony_cistatic void dispc_mgr_write_gamma_table(struct dispc_device *dispc,
380862306a36Sopenharmony_ci					enum omap_channel channel)
380962306a36Sopenharmony_ci{
381062306a36Sopenharmony_ci	const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
381162306a36Sopenharmony_ci	u32 *table = dispc->gamma_table[channel];
381262306a36Sopenharmony_ci	unsigned int i;
381362306a36Sopenharmony_ci
381462306a36Sopenharmony_ci	DSSDBG("%s: channel %d\n", __func__, channel);
381562306a36Sopenharmony_ci
381662306a36Sopenharmony_ci	for (i = 0; i < gdesc->len; ++i) {
381762306a36Sopenharmony_ci		u32 v = table[i];
381862306a36Sopenharmony_ci
381962306a36Sopenharmony_ci		if (gdesc->has_index)
382062306a36Sopenharmony_ci			v |= i << 24;
382162306a36Sopenharmony_ci		else if (i == 0)
382262306a36Sopenharmony_ci			v |= 1 << 31;
382362306a36Sopenharmony_ci
382462306a36Sopenharmony_ci		dispc_write_reg(dispc, gdesc->reg, v);
382562306a36Sopenharmony_ci	}
382662306a36Sopenharmony_ci}
382762306a36Sopenharmony_ci
382862306a36Sopenharmony_cistatic void dispc_restore_gamma_tables(struct dispc_device *dispc)
382962306a36Sopenharmony_ci{
383062306a36Sopenharmony_ci	DSSDBG("%s()\n", __func__);
383162306a36Sopenharmony_ci
383262306a36Sopenharmony_ci	if (!dispc->feat->has_gamma_table)
383362306a36Sopenharmony_ci		return;
383462306a36Sopenharmony_ci
383562306a36Sopenharmony_ci	dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_LCD);
383662306a36Sopenharmony_ci
383762306a36Sopenharmony_ci	dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_DIGIT);
383862306a36Sopenharmony_ci
383962306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_MGR_LCD2))
384062306a36Sopenharmony_ci		dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_LCD2);
384162306a36Sopenharmony_ci
384262306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_MGR_LCD3))
384362306a36Sopenharmony_ci		dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_LCD3);
384462306a36Sopenharmony_ci}
384562306a36Sopenharmony_ci
384662306a36Sopenharmony_cistatic const struct drm_color_lut dispc_mgr_gamma_default_lut[] = {
384762306a36Sopenharmony_ci	{ .red = 0, .green = 0, .blue = 0, },
384862306a36Sopenharmony_ci	{ .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, },
384962306a36Sopenharmony_ci};
385062306a36Sopenharmony_ci
385162306a36Sopenharmony_civoid dispc_mgr_set_gamma(struct dispc_device *dispc,
385262306a36Sopenharmony_ci				enum omap_channel channel,
385362306a36Sopenharmony_ci				const struct drm_color_lut *lut,
385462306a36Sopenharmony_ci				unsigned int length)
385562306a36Sopenharmony_ci{
385662306a36Sopenharmony_ci	const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
385762306a36Sopenharmony_ci	u32 *table = dispc->gamma_table[channel];
385862306a36Sopenharmony_ci	uint i;
385962306a36Sopenharmony_ci
386062306a36Sopenharmony_ci	DSSDBG("%s: channel %d, lut len %u, hw len %u\n", __func__,
386162306a36Sopenharmony_ci	       channel, length, gdesc->len);
386262306a36Sopenharmony_ci
386362306a36Sopenharmony_ci	if (!dispc->feat->has_gamma_table)
386462306a36Sopenharmony_ci		return;
386562306a36Sopenharmony_ci
386662306a36Sopenharmony_ci	if (lut == NULL || length < 2) {
386762306a36Sopenharmony_ci		lut = dispc_mgr_gamma_default_lut;
386862306a36Sopenharmony_ci		length = ARRAY_SIZE(dispc_mgr_gamma_default_lut);
386962306a36Sopenharmony_ci	}
387062306a36Sopenharmony_ci
387162306a36Sopenharmony_ci	for (i = 0; i < length - 1; ++i) {
387262306a36Sopenharmony_ci		uint first = i * (gdesc->len - 1) / (length - 1);
387362306a36Sopenharmony_ci		uint last = (i + 1) * (gdesc->len - 1) / (length - 1);
387462306a36Sopenharmony_ci		uint w = last - first;
387562306a36Sopenharmony_ci		u16 r, g, b;
387662306a36Sopenharmony_ci		uint j;
387762306a36Sopenharmony_ci
387862306a36Sopenharmony_ci		if (w == 0)
387962306a36Sopenharmony_ci			continue;
388062306a36Sopenharmony_ci
388162306a36Sopenharmony_ci		for (j = 0; j <= w; j++) {
388262306a36Sopenharmony_ci			r = (lut[i].red * (w - j) + lut[i+1].red * j) / w;
388362306a36Sopenharmony_ci			g = (lut[i].green * (w - j) + lut[i+1].green * j) / w;
388462306a36Sopenharmony_ci			b = (lut[i].blue * (w - j) + lut[i+1].blue * j) / w;
388562306a36Sopenharmony_ci
388662306a36Sopenharmony_ci			r >>= 16 - gdesc->bits;
388762306a36Sopenharmony_ci			g >>= 16 - gdesc->bits;
388862306a36Sopenharmony_ci			b >>= 16 - gdesc->bits;
388962306a36Sopenharmony_ci
389062306a36Sopenharmony_ci			table[first + j] = (r << (gdesc->bits * 2)) |
389162306a36Sopenharmony_ci				(g << gdesc->bits) | b;
389262306a36Sopenharmony_ci		}
389362306a36Sopenharmony_ci	}
389462306a36Sopenharmony_ci
389562306a36Sopenharmony_ci	if (dispc->is_enabled)
389662306a36Sopenharmony_ci		dispc_mgr_write_gamma_table(dispc, channel);
389762306a36Sopenharmony_ci}
389862306a36Sopenharmony_ci
389962306a36Sopenharmony_cistatic int dispc_init_gamma_tables(struct dispc_device *dispc)
390062306a36Sopenharmony_ci{
390162306a36Sopenharmony_ci	int channel;
390262306a36Sopenharmony_ci
390362306a36Sopenharmony_ci	if (!dispc->feat->has_gamma_table)
390462306a36Sopenharmony_ci		return 0;
390562306a36Sopenharmony_ci
390662306a36Sopenharmony_ci	for (channel = 0; channel < ARRAY_SIZE(dispc->gamma_table); channel++) {
390762306a36Sopenharmony_ci		const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
390862306a36Sopenharmony_ci		u32 *gt;
390962306a36Sopenharmony_ci
391062306a36Sopenharmony_ci		if (channel == OMAP_DSS_CHANNEL_LCD2 &&
391162306a36Sopenharmony_ci		    !dispc_has_feature(dispc, FEAT_MGR_LCD2))
391262306a36Sopenharmony_ci			continue;
391362306a36Sopenharmony_ci
391462306a36Sopenharmony_ci		if (channel == OMAP_DSS_CHANNEL_LCD3 &&
391562306a36Sopenharmony_ci		    !dispc_has_feature(dispc, FEAT_MGR_LCD3))
391662306a36Sopenharmony_ci			continue;
391762306a36Sopenharmony_ci
391862306a36Sopenharmony_ci		gt = devm_kmalloc_array(&dispc->pdev->dev, gdesc->len,
391962306a36Sopenharmony_ci					sizeof(u32), GFP_KERNEL);
392062306a36Sopenharmony_ci		if (!gt)
392162306a36Sopenharmony_ci			return -ENOMEM;
392262306a36Sopenharmony_ci
392362306a36Sopenharmony_ci		dispc->gamma_table[channel] = gt;
392462306a36Sopenharmony_ci
392562306a36Sopenharmony_ci		dispc_mgr_set_gamma(dispc, channel, NULL, 0);
392662306a36Sopenharmony_ci	}
392762306a36Sopenharmony_ci	return 0;
392862306a36Sopenharmony_ci}
392962306a36Sopenharmony_ci
393062306a36Sopenharmony_cistatic void _omap_dispc_initial_config(struct dispc_device *dispc)
393162306a36Sopenharmony_ci{
393262306a36Sopenharmony_ci	u32 l;
393362306a36Sopenharmony_ci
393462306a36Sopenharmony_ci	/* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
393562306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) {
393662306a36Sopenharmony_ci		l = dispc_read_reg(dispc, DISPC_DIVISOR);
393762306a36Sopenharmony_ci		/* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
393862306a36Sopenharmony_ci		l = FLD_MOD(l, 1, 0, 0);
393962306a36Sopenharmony_ci		l = FLD_MOD(l, 1, 23, 16);
394062306a36Sopenharmony_ci		dispc_write_reg(dispc, DISPC_DIVISOR, l);
394162306a36Sopenharmony_ci
394262306a36Sopenharmony_ci		dispc->core_clk_rate = dispc_fclk_rate(dispc);
394362306a36Sopenharmony_ci	}
394462306a36Sopenharmony_ci
394562306a36Sopenharmony_ci	/* Use gamma table mode, instead of palette mode */
394662306a36Sopenharmony_ci	if (dispc->feat->has_gamma_table)
394762306a36Sopenharmony_ci		REG_FLD_MOD(dispc, DISPC_CONFIG, 1, 3, 3);
394862306a36Sopenharmony_ci
394962306a36Sopenharmony_ci	/* For older DSS versions (FEAT_FUNCGATED) this enables
395062306a36Sopenharmony_ci	 * func-clock auto-gating. For newer versions
395162306a36Sopenharmony_ci	 * (dispc->feat->has_gamma_table) this enables tv-out gamma tables.
395262306a36Sopenharmony_ci	 */
395362306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_FUNCGATED) ||
395462306a36Sopenharmony_ci	    dispc->feat->has_gamma_table)
395562306a36Sopenharmony_ci		REG_FLD_MOD(dispc, DISPC_CONFIG, 1, 9, 9);
395662306a36Sopenharmony_ci
395762306a36Sopenharmony_ci	dispc_set_loadmode(dispc, OMAP_DSS_LOAD_FRAME_ONLY);
395862306a36Sopenharmony_ci
395962306a36Sopenharmony_ci	dispc_init_fifos(dispc);
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_ci	dispc_configure_burst_sizes(dispc);
396262306a36Sopenharmony_ci
396362306a36Sopenharmony_ci	dispc_ovl_enable_zorder_planes(dispc);
396462306a36Sopenharmony_ci
396562306a36Sopenharmony_ci	if (dispc->feat->mstandby_workaround)
396662306a36Sopenharmony_ci		REG_FLD_MOD(dispc, DISPC_MSTANDBY_CTRL, 1, 0, 0);
396762306a36Sopenharmony_ci
396862306a36Sopenharmony_ci	if (dispc_has_feature(dispc, FEAT_MFLAG))
396962306a36Sopenharmony_ci		dispc_init_mflag(dispc);
397062306a36Sopenharmony_ci}
397162306a36Sopenharmony_ci
397262306a36Sopenharmony_cistatic const enum dispc_feature_id omap2_dispc_features_list[] = {
397362306a36Sopenharmony_ci	FEAT_LCDENABLEPOL,
397462306a36Sopenharmony_ci	FEAT_LCDENABLESIGNAL,
397562306a36Sopenharmony_ci	FEAT_PCKFREEENABLE,
397662306a36Sopenharmony_ci	FEAT_FUNCGATED,
397762306a36Sopenharmony_ci	FEAT_ROWREPEATENABLE,
397862306a36Sopenharmony_ci	FEAT_RESIZECONF,
397962306a36Sopenharmony_ci};
398062306a36Sopenharmony_ci
398162306a36Sopenharmony_cistatic const enum dispc_feature_id omap3_dispc_features_list[] = {
398262306a36Sopenharmony_ci	FEAT_LCDENABLEPOL,
398362306a36Sopenharmony_ci	FEAT_LCDENABLESIGNAL,
398462306a36Sopenharmony_ci	FEAT_PCKFREEENABLE,
398562306a36Sopenharmony_ci	FEAT_FUNCGATED,
398662306a36Sopenharmony_ci	FEAT_LINEBUFFERSPLIT,
398762306a36Sopenharmony_ci	FEAT_ROWREPEATENABLE,
398862306a36Sopenharmony_ci	FEAT_RESIZECONF,
398962306a36Sopenharmony_ci	FEAT_CPR,
399062306a36Sopenharmony_ci	FEAT_PRELOAD,
399162306a36Sopenharmony_ci	FEAT_FIR_COEF_V,
399262306a36Sopenharmony_ci	FEAT_ALPHA_FIXED_ZORDER,
399362306a36Sopenharmony_ci	FEAT_FIFO_MERGE,
399462306a36Sopenharmony_ci	FEAT_OMAP3_DSI_FIFO_BUG,
399562306a36Sopenharmony_ci};
399662306a36Sopenharmony_ci
399762306a36Sopenharmony_cistatic const enum dispc_feature_id am43xx_dispc_features_list[] = {
399862306a36Sopenharmony_ci	FEAT_LCDENABLEPOL,
399962306a36Sopenharmony_ci	FEAT_LCDENABLESIGNAL,
400062306a36Sopenharmony_ci	FEAT_PCKFREEENABLE,
400162306a36Sopenharmony_ci	FEAT_FUNCGATED,
400262306a36Sopenharmony_ci	FEAT_LINEBUFFERSPLIT,
400362306a36Sopenharmony_ci	FEAT_ROWREPEATENABLE,
400462306a36Sopenharmony_ci	FEAT_RESIZECONF,
400562306a36Sopenharmony_ci	FEAT_CPR,
400662306a36Sopenharmony_ci	FEAT_PRELOAD,
400762306a36Sopenharmony_ci	FEAT_FIR_COEF_V,
400862306a36Sopenharmony_ci	FEAT_ALPHA_FIXED_ZORDER,
400962306a36Sopenharmony_ci	FEAT_FIFO_MERGE,
401062306a36Sopenharmony_ci};
401162306a36Sopenharmony_ci
401262306a36Sopenharmony_cistatic const enum dispc_feature_id omap4_dispc_features_list[] = {
401362306a36Sopenharmony_ci	FEAT_MGR_LCD2,
401462306a36Sopenharmony_ci	FEAT_CORE_CLK_DIV,
401562306a36Sopenharmony_ci	FEAT_HANDLE_UV_SEPARATE,
401662306a36Sopenharmony_ci	FEAT_ATTR2,
401762306a36Sopenharmony_ci	FEAT_CPR,
401862306a36Sopenharmony_ci	FEAT_PRELOAD,
401962306a36Sopenharmony_ci	FEAT_FIR_COEF_V,
402062306a36Sopenharmony_ci	FEAT_ALPHA_FREE_ZORDER,
402162306a36Sopenharmony_ci	FEAT_FIFO_MERGE,
402262306a36Sopenharmony_ci	FEAT_BURST_2D,
402362306a36Sopenharmony_ci};
402462306a36Sopenharmony_ci
402562306a36Sopenharmony_cistatic const enum dispc_feature_id omap5_dispc_features_list[] = {
402662306a36Sopenharmony_ci	FEAT_MGR_LCD2,
402762306a36Sopenharmony_ci	FEAT_MGR_LCD3,
402862306a36Sopenharmony_ci	FEAT_CORE_CLK_DIV,
402962306a36Sopenharmony_ci	FEAT_HANDLE_UV_SEPARATE,
403062306a36Sopenharmony_ci	FEAT_ATTR2,
403162306a36Sopenharmony_ci	FEAT_CPR,
403262306a36Sopenharmony_ci	FEAT_PRELOAD,
403362306a36Sopenharmony_ci	FEAT_FIR_COEF_V,
403462306a36Sopenharmony_ci	FEAT_ALPHA_FREE_ZORDER,
403562306a36Sopenharmony_ci	FEAT_FIFO_MERGE,
403662306a36Sopenharmony_ci	FEAT_BURST_2D,
403762306a36Sopenharmony_ci	FEAT_MFLAG,
403862306a36Sopenharmony_ci};
403962306a36Sopenharmony_ci
404062306a36Sopenharmony_cistatic const struct dss_reg_field omap2_dispc_reg_fields[] = {
404162306a36Sopenharmony_ci	[FEAT_REG_FIRHINC]			= { 11, 0 },
404262306a36Sopenharmony_ci	[FEAT_REG_FIRVINC]			= { 27, 16 },
404362306a36Sopenharmony_ci	[FEAT_REG_FIFOLOWTHRESHOLD]		= { 8, 0 },
404462306a36Sopenharmony_ci	[FEAT_REG_FIFOHIGHTHRESHOLD]		= { 24, 16 },
404562306a36Sopenharmony_ci	[FEAT_REG_FIFOSIZE]			= { 8, 0 },
404662306a36Sopenharmony_ci	[FEAT_REG_HORIZONTALACCU]		= { 9, 0 },
404762306a36Sopenharmony_ci	[FEAT_REG_VERTICALACCU]			= { 25, 16 },
404862306a36Sopenharmony_ci};
404962306a36Sopenharmony_ci
405062306a36Sopenharmony_cistatic const struct dss_reg_field omap3_dispc_reg_fields[] = {
405162306a36Sopenharmony_ci	[FEAT_REG_FIRHINC]			= { 12, 0 },
405262306a36Sopenharmony_ci	[FEAT_REG_FIRVINC]			= { 28, 16 },
405362306a36Sopenharmony_ci	[FEAT_REG_FIFOLOWTHRESHOLD]		= { 11, 0 },
405462306a36Sopenharmony_ci	[FEAT_REG_FIFOHIGHTHRESHOLD]		= { 27, 16 },
405562306a36Sopenharmony_ci	[FEAT_REG_FIFOSIZE]			= { 10, 0 },
405662306a36Sopenharmony_ci	[FEAT_REG_HORIZONTALACCU]		= { 9, 0 },
405762306a36Sopenharmony_ci	[FEAT_REG_VERTICALACCU]			= { 25, 16 },
405862306a36Sopenharmony_ci};
405962306a36Sopenharmony_ci
406062306a36Sopenharmony_cistatic const struct dss_reg_field omap4_dispc_reg_fields[] = {
406162306a36Sopenharmony_ci	[FEAT_REG_FIRHINC]			= { 12, 0 },
406262306a36Sopenharmony_ci	[FEAT_REG_FIRVINC]			= { 28, 16 },
406362306a36Sopenharmony_ci	[FEAT_REG_FIFOLOWTHRESHOLD]		= { 15, 0 },
406462306a36Sopenharmony_ci	[FEAT_REG_FIFOHIGHTHRESHOLD]		= { 31, 16 },
406562306a36Sopenharmony_ci	[FEAT_REG_FIFOSIZE]			= { 15, 0 },
406662306a36Sopenharmony_ci	[FEAT_REG_HORIZONTALACCU]		= { 10, 0 },
406762306a36Sopenharmony_ci	[FEAT_REG_VERTICALACCU]			= { 26, 16 },
406862306a36Sopenharmony_ci};
406962306a36Sopenharmony_ci
407062306a36Sopenharmony_cistatic const enum omap_overlay_caps omap2_dispc_overlay_caps[] = {
407162306a36Sopenharmony_ci	/* OMAP_DSS_GFX */
407262306a36Sopenharmony_ci	OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
407362306a36Sopenharmony_ci
407462306a36Sopenharmony_ci	/* OMAP_DSS_VIDEO1 */
407562306a36Sopenharmony_ci	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
407662306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_REPLICATION,
407762306a36Sopenharmony_ci
407862306a36Sopenharmony_ci	/* OMAP_DSS_VIDEO2 */
407962306a36Sopenharmony_ci	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
408062306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_REPLICATION,
408162306a36Sopenharmony_ci};
408262306a36Sopenharmony_ci
408362306a36Sopenharmony_cistatic const enum omap_overlay_caps omap3430_dispc_overlay_caps[] = {
408462306a36Sopenharmony_ci	/* OMAP_DSS_GFX */
408562306a36Sopenharmony_ci	OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_POS |
408662306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_REPLICATION,
408762306a36Sopenharmony_ci
408862306a36Sopenharmony_ci	/* OMAP_DSS_VIDEO1 */
408962306a36Sopenharmony_ci	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
409062306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_REPLICATION,
409162306a36Sopenharmony_ci
409262306a36Sopenharmony_ci	/* OMAP_DSS_VIDEO2 */
409362306a36Sopenharmony_ci	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
409462306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
409562306a36Sopenharmony_ci};
409662306a36Sopenharmony_ci
409762306a36Sopenharmony_cistatic const enum omap_overlay_caps omap3630_dispc_overlay_caps[] = {
409862306a36Sopenharmony_ci	/* OMAP_DSS_GFX */
409962306a36Sopenharmony_ci	OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
410062306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
410162306a36Sopenharmony_ci
410262306a36Sopenharmony_ci	/* OMAP_DSS_VIDEO1 */
410362306a36Sopenharmony_ci	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
410462306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_REPLICATION,
410562306a36Sopenharmony_ci
410662306a36Sopenharmony_ci	/* OMAP_DSS_VIDEO2 */
410762306a36Sopenharmony_ci	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
410862306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_POS |
410962306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_REPLICATION,
411062306a36Sopenharmony_ci};
411162306a36Sopenharmony_ci
411262306a36Sopenharmony_cistatic const enum omap_overlay_caps omap4_dispc_overlay_caps[] = {
411362306a36Sopenharmony_ci	/* OMAP_DSS_GFX */
411462306a36Sopenharmony_ci	OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
411562306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_ZORDER | OMAP_DSS_OVL_CAP_POS |
411662306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_REPLICATION,
411762306a36Sopenharmony_ci
411862306a36Sopenharmony_ci	/* OMAP_DSS_VIDEO1 */
411962306a36Sopenharmony_ci	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
412062306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
412162306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
412262306a36Sopenharmony_ci
412362306a36Sopenharmony_ci	/* OMAP_DSS_VIDEO2 */
412462306a36Sopenharmony_ci	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
412562306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
412662306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
412762306a36Sopenharmony_ci
412862306a36Sopenharmony_ci	/* OMAP_DSS_VIDEO3 */
412962306a36Sopenharmony_ci	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
413062306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
413162306a36Sopenharmony_ci		OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
413262306a36Sopenharmony_ci};
413362306a36Sopenharmony_ci
413462306a36Sopenharmony_ci#define COLOR_ARRAY(arr...) (const u32[]) { arr, 0 }
413562306a36Sopenharmony_ci
413662306a36Sopenharmony_cistatic const u32 *omap2_dispc_supported_color_modes[] = {
413762306a36Sopenharmony_ci
413862306a36Sopenharmony_ci	/* OMAP_DSS_GFX */
413962306a36Sopenharmony_ci	COLOR_ARRAY(
414062306a36Sopenharmony_ci	DRM_FORMAT_RGBX4444, DRM_FORMAT_RGB565,
414162306a36Sopenharmony_ci	DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB888),
414262306a36Sopenharmony_ci
414362306a36Sopenharmony_ci	/* OMAP_DSS_VIDEO1 */
414462306a36Sopenharmony_ci	COLOR_ARRAY(
414562306a36Sopenharmony_ci	DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888,
414662306a36Sopenharmony_ci	DRM_FORMAT_RGB888, DRM_FORMAT_YUYV,
414762306a36Sopenharmony_ci	DRM_FORMAT_UYVY),
414862306a36Sopenharmony_ci
414962306a36Sopenharmony_ci	/* OMAP_DSS_VIDEO2 */
415062306a36Sopenharmony_ci	COLOR_ARRAY(
415162306a36Sopenharmony_ci	DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888,
415262306a36Sopenharmony_ci	DRM_FORMAT_RGB888, DRM_FORMAT_YUYV,
415362306a36Sopenharmony_ci	DRM_FORMAT_UYVY),
415462306a36Sopenharmony_ci};
415562306a36Sopenharmony_ci
415662306a36Sopenharmony_cistatic const u32 *omap3_dispc_supported_color_modes[] = {
415762306a36Sopenharmony_ci	/* OMAP_DSS_GFX */
415862306a36Sopenharmony_ci	COLOR_ARRAY(
415962306a36Sopenharmony_ci	DRM_FORMAT_RGBX4444, DRM_FORMAT_ARGB4444,
416062306a36Sopenharmony_ci	DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888,
416162306a36Sopenharmony_ci	DRM_FORMAT_RGB888, DRM_FORMAT_ARGB8888,
416262306a36Sopenharmony_ci	DRM_FORMAT_RGBA8888, DRM_FORMAT_RGBX8888),
416362306a36Sopenharmony_ci
416462306a36Sopenharmony_ci	/* OMAP_DSS_VIDEO1 */
416562306a36Sopenharmony_ci	COLOR_ARRAY(
416662306a36Sopenharmony_ci	DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB888,
416762306a36Sopenharmony_ci	DRM_FORMAT_RGBX4444, DRM_FORMAT_RGB565,
416862306a36Sopenharmony_ci	DRM_FORMAT_YUYV, DRM_FORMAT_UYVY),
416962306a36Sopenharmony_ci
417062306a36Sopenharmony_ci	/* OMAP_DSS_VIDEO2 */
417162306a36Sopenharmony_ci	COLOR_ARRAY(
417262306a36Sopenharmony_ci	DRM_FORMAT_RGBX4444, DRM_FORMAT_ARGB4444,
417362306a36Sopenharmony_ci	DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888,
417462306a36Sopenharmony_ci	DRM_FORMAT_RGB888, DRM_FORMAT_YUYV,
417562306a36Sopenharmony_ci	DRM_FORMAT_UYVY, DRM_FORMAT_ARGB8888,
417662306a36Sopenharmony_ci	DRM_FORMAT_RGBA8888, DRM_FORMAT_RGBX8888),
417762306a36Sopenharmony_ci};
417862306a36Sopenharmony_ci
417962306a36Sopenharmony_cistatic const u32 *omap4_dispc_supported_color_modes[] = {
418062306a36Sopenharmony_ci	/* OMAP_DSS_GFX */
418162306a36Sopenharmony_ci	COLOR_ARRAY(
418262306a36Sopenharmony_ci	DRM_FORMAT_RGBX4444, DRM_FORMAT_ARGB4444,
418362306a36Sopenharmony_ci	DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888,
418462306a36Sopenharmony_ci	DRM_FORMAT_RGB888, DRM_FORMAT_ARGB8888,
418562306a36Sopenharmony_ci	DRM_FORMAT_RGBA8888, DRM_FORMAT_RGBX8888,
418662306a36Sopenharmony_ci	DRM_FORMAT_ARGB1555, DRM_FORMAT_XRGB4444,
418762306a36Sopenharmony_ci	DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB1555),
418862306a36Sopenharmony_ci
418962306a36Sopenharmony_ci	/* OMAP_DSS_VIDEO1 */
419062306a36Sopenharmony_ci	COLOR_ARRAY(
419162306a36Sopenharmony_ci	DRM_FORMAT_RGB565, DRM_FORMAT_RGBX4444,
419262306a36Sopenharmony_ci	DRM_FORMAT_YUYV, DRM_FORMAT_ARGB1555,
419362306a36Sopenharmony_ci	DRM_FORMAT_RGBA8888, DRM_FORMAT_NV12,
419462306a36Sopenharmony_ci	DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB8888,
419562306a36Sopenharmony_ci	DRM_FORMAT_RGB888, DRM_FORMAT_UYVY,
419662306a36Sopenharmony_ci	DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555,
419762306a36Sopenharmony_ci	DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB4444,
419862306a36Sopenharmony_ci	DRM_FORMAT_RGBX8888),
419962306a36Sopenharmony_ci
420062306a36Sopenharmony_ci       /* OMAP_DSS_VIDEO2 */
420162306a36Sopenharmony_ci	COLOR_ARRAY(
420262306a36Sopenharmony_ci	DRM_FORMAT_RGB565, DRM_FORMAT_RGBX4444,
420362306a36Sopenharmony_ci	DRM_FORMAT_YUYV, DRM_FORMAT_ARGB1555,
420462306a36Sopenharmony_ci	DRM_FORMAT_RGBA8888, DRM_FORMAT_NV12,
420562306a36Sopenharmony_ci	DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB8888,
420662306a36Sopenharmony_ci	DRM_FORMAT_RGB888, DRM_FORMAT_UYVY,
420762306a36Sopenharmony_ci	DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555,
420862306a36Sopenharmony_ci	DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB4444,
420962306a36Sopenharmony_ci	DRM_FORMAT_RGBX8888),
421062306a36Sopenharmony_ci
421162306a36Sopenharmony_ci	/* OMAP_DSS_VIDEO3 */
421262306a36Sopenharmony_ci	COLOR_ARRAY(
421362306a36Sopenharmony_ci	DRM_FORMAT_RGB565, DRM_FORMAT_RGBX4444,
421462306a36Sopenharmony_ci	DRM_FORMAT_YUYV, DRM_FORMAT_ARGB1555,
421562306a36Sopenharmony_ci	DRM_FORMAT_RGBA8888, DRM_FORMAT_NV12,
421662306a36Sopenharmony_ci	DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB8888,
421762306a36Sopenharmony_ci	DRM_FORMAT_RGB888, DRM_FORMAT_UYVY,
421862306a36Sopenharmony_ci	DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555,
421962306a36Sopenharmony_ci	DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB4444,
422062306a36Sopenharmony_ci	DRM_FORMAT_RGBX8888),
422162306a36Sopenharmony_ci
422262306a36Sopenharmony_ci	/* OMAP_DSS_WB */
422362306a36Sopenharmony_ci	COLOR_ARRAY(
422462306a36Sopenharmony_ci	DRM_FORMAT_RGB565, DRM_FORMAT_RGBX4444,
422562306a36Sopenharmony_ci	DRM_FORMAT_YUYV, DRM_FORMAT_ARGB1555,
422662306a36Sopenharmony_ci	DRM_FORMAT_RGBA8888, DRM_FORMAT_NV12,
422762306a36Sopenharmony_ci	DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB8888,
422862306a36Sopenharmony_ci	DRM_FORMAT_RGB888, DRM_FORMAT_UYVY,
422962306a36Sopenharmony_ci	DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555,
423062306a36Sopenharmony_ci	DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB4444,
423162306a36Sopenharmony_ci	DRM_FORMAT_RGBX8888),
423262306a36Sopenharmony_ci};
423362306a36Sopenharmony_ci
423462306a36Sopenharmony_cistatic const u32 omap3_dispc_supported_scaler_color_modes[] = {
423562306a36Sopenharmony_ci	DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB565, DRM_FORMAT_YUYV,
423662306a36Sopenharmony_ci	DRM_FORMAT_UYVY,
423762306a36Sopenharmony_ci	0,
423862306a36Sopenharmony_ci};
423962306a36Sopenharmony_ci
424062306a36Sopenharmony_cistatic const struct dispc_features omap24xx_dispc_feats = {
424162306a36Sopenharmony_ci	.sw_start		=	5,
424262306a36Sopenharmony_ci	.fp_start		=	15,
424362306a36Sopenharmony_ci	.bp_start		=	27,
424462306a36Sopenharmony_ci	.sw_max			=	64,
424562306a36Sopenharmony_ci	.vp_max			=	255,
424662306a36Sopenharmony_ci	.hp_max			=	256,
424762306a36Sopenharmony_ci	.mgr_width_start	=	10,
424862306a36Sopenharmony_ci	.mgr_height_start	=	26,
424962306a36Sopenharmony_ci	.mgr_width_max		=	2048,
425062306a36Sopenharmony_ci	.mgr_height_max		=	2048,
425162306a36Sopenharmony_ci	.ovl_width_max		=	2048,
425262306a36Sopenharmony_ci	.ovl_height_max		=	2048,
425362306a36Sopenharmony_ci	.max_lcd_pclk		=	66500000,
425462306a36Sopenharmony_ci	.max_downscale		=	2,
425562306a36Sopenharmony_ci	/*
425662306a36Sopenharmony_ci	 * Assume the line width buffer to be 768 pixels as OMAP2 DISPC scaler
425762306a36Sopenharmony_ci	 * cannot scale an image width larger than 768.
425862306a36Sopenharmony_ci	 */
425962306a36Sopenharmony_ci	.max_line_width		=	768,
426062306a36Sopenharmony_ci	.min_pcd		=	2,
426162306a36Sopenharmony_ci	.calc_scaling		=	dispc_ovl_calc_scaling_24xx,
426262306a36Sopenharmony_ci	.calc_core_clk		=	calc_core_clk_24xx,
426362306a36Sopenharmony_ci	.num_fifos		=	3,
426462306a36Sopenharmony_ci	.features		=	omap2_dispc_features_list,
426562306a36Sopenharmony_ci	.num_features		=	ARRAY_SIZE(omap2_dispc_features_list),
426662306a36Sopenharmony_ci	.reg_fields		=	omap2_dispc_reg_fields,
426762306a36Sopenharmony_ci	.num_reg_fields		=	ARRAY_SIZE(omap2_dispc_reg_fields),
426862306a36Sopenharmony_ci	.overlay_caps		=	omap2_dispc_overlay_caps,
426962306a36Sopenharmony_ci	.supported_color_modes	=	omap2_dispc_supported_color_modes,
427062306a36Sopenharmony_ci	.supported_scaler_color_modes = COLOR_ARRAY(DRM_FORMAT_XRGB8888),
427162306a36Sopenharmony_ci	.num_mgrs		=	2,
427262306a36Sopenharmony_ci	.num_ovls		=	3,
427362306a36Sopenharmony_ci	.buffer_size_unit	=	1,
427462306a36Sopenharmony_ci	.burst_size_unit	=	8,
427562306a36Sopenharmony_ci	.no_framedone_tv	=	true,
427662306a36Sopenharmony_ci	.set_max_preload	=	false,
427762306a36Sopenharmony_ci	.last_pixel_inc_missing	=	true,
427862306a36Sopenharmony_ci};
427962306a36Sopenharmony_ci
428062306a36Sopenharmony_cistatic const struct dispc_features omap34xx_rev1_0_dispc_feats = {
428162306a36Sopenharmony_ci	.sw_start		=	5,
428262306a36Sopenharmony_ci	.fp_start		=	15,
428362306a36Sopenharmony_ci	.bp_start		=	27,
428462306a36Sopenharmony_ci	.sw_max			=	64,
428562306a36Sopenharmony_ci	.vp_max			=	255,
428662306a36Sopenharmony_ci	.hp_max			=	256,
428762306a36Sopenharmony_ci	.mgr_width_start	=	10,
428862306a36Sopenharmony_ci	.mgr_height_start	=	26,
428962306a36Sopenharmony_ci	.mgr_width_max		=	2048,
429062306a36Sopenharmony_ci	.mgr_height_max		=	2048,
429162306a36Sopenharmony_ci	.ovl_width_max		=	2048,
429262306a36Sopenharmony_ci	.ovl_height_max		=	2048,
429362306a36Sopenharmony_ci	.max_lcd_pclk		=	173000000,
429462306a36Sopenharmony_ci	.max_tv_pclk		=	59000000,
429562306a36Sopenharmony_ci	.max_downscale		=	4,
429662306a36Sopenharmony_ci	.max_line_width		=	1024,
429762306a36Sopenharmony_ci	.min_pcd		=	1,
429862306a36Sopenharmony_ci	.calc_scaling		=	dispc_ovl_calc_scaling_34xx,
429962306a36Sopenharmony_ci	.calc_core_clk		=	calc_core_clk_34xx,
430062306a36Sopenharmony_ci	.num_fifos		=	3,
430162306a36Sopenharmony_ci	.features		=	omap3_dispc_features_list,
430262306a36Sopenharmony_ci	.num_features		=	ARRAY_SIZE(omap3_dispc_features_list),
430362306a36Sopenharmony_ci	.reg_fields		=	omap3_dispc_reg_fields,
430462306a36Sopenharmony_ci	.num_reg_fields		=	ARRAY_SIZE(omap3_dispc_reg_fields),
430562306a36Sopenharmony_ci	.overlay_caps		=	omap3430_dispc_overlay_caps,
430662306a36Sopenharmony_ci	.supported_color_modes	=	omap3_dispc_supported_color_modes,
430762306a36Sopenharmony_ci	.supported_scaler_color_modes = omap3_dispc_supported_scaler_color_modes,
430862306a36Sopenharmony_ci	.num_mgrs		=	2,
430962306a36Sopenharmony_ci	.num_ovls		=	3,
431062306a36Sopenharmony_ci	.buffer_size_unit	=	1,
431162306a36Sopenharmony_ci	.burst_size_unit	=	8,
431262306a36Sopenharmony_ci	.no_framedone_tv	=	true,
431362306a36Sopenharmony_ci	.set_max_preload	=	false,
431462306a36Sopenharmony_ci	.last_pixel_inc_missing	=	true,
431562306a36Sopenharmony_ci};
431662306a36Sopenharmony_ci
431762306a36Sopenharmony_cistatic const struct dispc_features omap34xx_rev3_0_dispc_feats = {
431862306a36Sopenharmony_ci	.sw_start		=	7,
431962306a36Sopenharmony_ci	.fp_start		=	19,
432062306a36Sopenharmony_ci	.bp_start		=	31,
432162306a36Sopenharmony_ci	.sw_max			=	256,
432262306a36Sopenharmony_ci	.vp_max			=	4095,
432362306a36Sopenharmony_ci	.hp_max			=	4096,
432462306a36Sopenharmony_ci	.mgr_width_start	=	10,
432562306a36Sopenharmony_ci	.mgr_height_start	=	26,
432662306a36Sopenharmony_ci	.mgr_width_max		=	2048,
432762306a36Sopenharmony_ci	.mgr_height_max		=	2048,
432862306a36Sopenharmony_ci	.ovl_width_max		=	2048,
432962306a36Sopenharmony_ci	.ovl_height_max		=	2048,
433062306a36Sopenharmony_ci	.max_lcd_pclk		=	173000000,
433162306a36Sopenharmony_ci	.max_tv_pclk		=	59000000,
433262306a36Sopenharmony_ci	.max_downscale		=	4,
433362306a36Sopenharmony_ci	.max_line_width		=	1024,
433462306a36Sopenharmony_ci	.min_pcd		=	1,
433562306a36Sopenharmony_ci	.calc_scaling		=	dispc_ovl_calc_scaling_34xx,
433662306a36Sopenharmony_ci	.calc_core_clk		=	calc_core_clk_34xx,
433762306a36Sopenharmony_ci	.num_fifos		=	3,
433862306a36Sopenharmony_ci	.features		=	omap3_dispc_features_list,
433962306a36Sopenharmony_ci	.num_features		=	ARRAY_SIZE(omap3_dispc_features_list),
434062306a36Sopenharmony_ci	.reg_fields		=	omap3_dispc_reg_fields,
434162306a36Sopenharmony_ci	.num_reg_fields		=	ARRAY_SIZE(omap3_dispc_reg_fields),
434262306a36Sopenharmony_ci	.overlay_caps		=	omap3430_dispc_overlay_caps,
434362306a36Sopenharmony_ci	.supported_color_modes	=	omap3_dispc_supported_color_modes,
434462306a36Sopenharmony_ci	.supported_scaler_color_modes = omap3_dispc_supported_scaler_color_modes,
434562306a36Sopenharmony_ci	.num_mgrs		=	2,
434662306a36Sopenharmony_ci	.num_ovls		=	3,
434762306a36Sopenharmony_ci	.buffer_size_unit	=	1,
434862306a36Sopenharmony_ci	.burst_size_unit	=	8,
434962306a36Sopenharmony_ci	.no_framedone_tv	=	true,
435062306a36Sopenharmony_ci	.set_max_preload	=	false,
435162306a36Sopenharmony_ci	.last_pixel_inc_missing	=	true,
435262306a36Sopenharmony_ci};
435362306a36Sopenharmony_ci
435462306a36Sopenharmony_cistatic const struct dispc_features omap36xx_dispc_feats = {
435562306a36Sopenharmony_ci	.sw_start		=	7,
435662306a36Sopenharmony_ci	.fp_start		=	19,
435762306a36Sopenharmony_ci	.bp_start		=	31,
435862306a36Sopenharmony_ci	.sw_max			=	256,
435962306a36Sopenharmony_ci	.vp_max			=	4095,
436062306a36Sopenharmony_ci	.hp_max			=	4096,
436162306a36Sopenharmony_ci	.mgr_width_start	=	10,
436262306a36Sopenharmony_ci	.mgr_height_start	=	26,
436362306a36Sopenharmony_ci	.mgr_width_max		=	2048,
436462306a36Sopenharmony_ci	.mgr_height_max		=	2048,
436562306a36Sopenharmony_ci	.ovl_width_max		=	2048,
436662306a36Sopenharmony_ci	.ovl_height_max		=	2048,
436762306a36Sopenharmony_ci	.max_lcd_pclk		=	173000000,
436862306a36Sopenharmony_ci	.max_tv_pclk		=	59000000,
436962306a36Sopenharmony_ci	.max_downscale		=	4,
437062306a36Sopenharmony_ci	.max_line_width		=	1024,
437162306a36Sopenharmony_ci	.min_pcd		=	1,
437262306a36Sopenharmony_ci	.calc_scaling		=	dispc_ovl_calc_scaling_34xx,
437362306a36Sopenharmony_ci	.calc_core_clk		=	calc_core_clk_34xx,
437462306a36Sopenharmony_ci	.num_fifos		=	3,
437562306a36Sopenharmony_ci	.features		=	omap3_dispc_features_list,
437662306a36Sopenharmony_ci	.num_features		=	ARRAY_SIZE(omap3_dispc_features_list),
437762306a36Sopenharmony_ci	.reg_fields		=	omap3_dispc_reg_fields,
437862306a36Sopenharmony_ci	.num_reg_fields		=	ARRAY_SIZE(omap3_dispc_reg_fields),
437962306a36Sopenharmony_ci	.overlay_caps		=	omap3630_dispc_overlay_caps,
438062306a36Sopenharmony_ci	.supported_color_modes	=	omap3_dispc_supported_color_modes,
438162306a36Sopenharmony_ci	.supported_scaler_color_modes = omap3_dispc_supported_scaler_color_modes,
438262306a36Sopenharmony_ci	.num_mgrs		=	2,
438362306a36Sopenharmony_ci	.num_ovls		=	3,
438462306a36Sopenharmony_ci	.buffer_size_unit	=	1,
438562306a36Sopenharmony_ci	.burst_size_unit	=	8,
438662306a36Sopenharmony_ci	.no_framedone_tv	=	true,
438762306a36Sopenharmony_ci	.set_max_preload	=	false,
438862306a36Sopenharmony_ci	.last_pixel_inc_missing	=	true,
438962306a36Sopenharmony_ci};
439062306a36Sopenharmony_ci
439162306a36Sopenharmony_cistatic const struct dispc_features am43xx_dispc_feats = {
439262306a36Sopenharmony_ci	.sw_start		=	7,
439362306a36Sopenharmony_ci	.fp_start		=	19,
439462306a36Sopenharmony_ci	.bp_start		=	31,
439562306a36Sopenharmony_ci	.sw_max			=	256,
439662306a36Sopenharmony_ci	.vp_max			=	4095,
439762306a36Sopenharmony_ci	.hp_max			=	4096,
439862306a36Sopenharmony_ci	.mgr_width_start	=	10,
439962306a36Sopenharmony_ci	.mgr_height_start	=	26,
440062306a36Sopenharmony_ci	.mgr_width_max		=	2048,
440162306a36Sopenharmony_ci	.mgr_height_max		=	2048,
440262306a36Sopenharmony_ci	.ovl_width_max		=	2048,
440362306a36Sopenharmony_ci	.ovl_height_max		=	2048,
440462306a36Sopenharmony_ci	.max_lcd_pclk		=	173000000,
440562306a36Sopenharmony_ci	.max_tv_pclk		=	59000000,
440662306a36Sopenharmony_ci	.max_downscale		=	4,
440762306a36Sopenharmony_ci	.max_line_width		=	1024,
440862306a36Sopenharmony_ci	.min_pcd		=	1,
440962306a36Sopenharmony_ci	.calc_scaling		=	dispc_ovl_calc_scaling_34xx,
441062306a36Sopenharmony_ci	.calc_core_clk		=	calc_core_clk_34xx,
441162306a36Sopenharmony_ci	.num_fifos		=	3,
441262306a36Sopenharmony_ci	.features		=	am43xx_dispc_features_list,
441362306a36Sopenharmony_ci	.num_features		=	ARRAY_SIZE(am43xx_dispc_features_list),
441462306a36Sopenharmony_ci	.reg_fields		=	omap3_dispc_reg_fields,
441562306a36Sopenharmony_ci	.num_reg_fields		=	ARRAY_SIZE(omap3_dispc_reg_fields),
441662306a36Sopenharmony_ci	.overlay_caps		=	omap3430_dispc_overlay_caps,
441762306a36Sopenharmony_ci	.supported_color_modes	=	omap3_dispc_supported_color_modes,
441862306a36Sopenharmony_ci	.supported_scaler_color_modes = omap3_dispc_supported_scaler_color_modes,
441962306a36Sopenharmony_ci	.num_mgrs		=	1,
442062306a36Sopenharmony_ci	.num_ovls		=	3,
442162306a36Sopenharmony_ci	.buffer_size_unit	=	1,
442262306a36Sopenharmony_ci	.burst_size_unit	=	8,
442362306a36Sopenharmony_ci	.no_framedone_tv	=	true,
442462306a36Sopenharmony_ci	.set_max_preload	=	false,
442562306a36Sopenharmony_ci	.last_pixel_inc_missing	=	true,
442662306a36Sopenharmony_ci};
442762306a36Sopenharmony_ci
442862306a36Sopenharmony_cistatic const struct dispc_features omap44xx_dispc_feats = {
442962306a36Sopenharmony_ci	.sw_start		=	7,
443062306a36Sopenharmony_ci	.fp_start		=	19,
443162306a36Sopenharmony_ci	.bp_start		=	31,
443262306a36Sopenharmony_ci	.sw_max			=	256,
443362306a36Sopenharmony_ci	.vp_max			=	4095,
443462306a36Sopenharmony_ci	.hp_max			=	4096,
443562306a36Sopenharmony_ci	.mgr_width_start	=	10,
443662306a36Sopenharmony_ci	.mgr_height_start	=	26,
443762306a36Sopenharmony_ci	.mgr_width_max		=	2048,
443862306a36Sopenharmony_ci	.mgr_height_max		=	2048,
443962306a36Sopenharmony_ci	.ovl_width_max		=	2048,
444062306a36Sopenharmony_ci	.ovl_height_max		=	2048,
444162306a36Sopenharmony_ci	.max_lcd_pclk		=	170000000,
444262306a36Sopenharmony_ci	.max_tv_pclk		=	185625000,
444362306a36Sopenharmony_ci	.max_downscale		=	4,
444462306a36Sopenharmony_ci	.max_line_width		=	2048,
444562306a36Sopenharmony_ci	.min_pcd		=	1,
444662306a36Sopenharmony_ci	.calc_scaling		=	dispc_ovl_calc_scaling_44xx,
444762306a36Sopenharmony_ci	.calc_core_clk		=	calc_core_clk_44xx,
444862306a36Sopenharmony_ci	.num_fifos		=	5,
444962306a36Sopenharmony_ci	.features		=	omap4_dispc_features_list,
445062306a36Sopenharmony_ci	.num_features		=	ARRAY_SIZE(omap4_dispc_features_list),
445162306a36Sopenharmony_ci	.reg_fields		=	omap4_dispc_reg_fields,
445262306a36Sopenharmony_ci	.num_reg_fields		=	ARRAY_SIZE(omap4_dispc_reg_fields),
445362306a36Sopenharmony_ci	.overlay_caps		=	omap4_dispc_overlay_caps,
445462306a36Sopenharmony_ci	.supported_color_modes	=	omap4_dispc_supported_color_modes,
445562306a36Sopenharmony_ci	.num_mgrs		=	3,
445662306a36Sopenharmony_ci	.num_ovls		=	4,
445762306a36Sopenharmony_ci	.buffer_size_unit	=	16,
445862306a36Sopenharmony_ci	.burst_size_unit	=	16,
445962306a36Sopenharmony_ci	.gfx_fifo_workaround	=	true,
446062306a36Sopenharmony_ci	.set_max_preload	=	true,
446162306a36Sopenharmony_ci	.supports_sync_align	=	true,
446262306a36Sopenharmony_ci	.has_writeback		=	true,
446362306a36Sopenharmony_ci	.supports_double_pixel	=	true,
446462306a36Sopenharmony_ci	.reverse_ilace_field_order =	true,
446562306a36Sopenharmony_ci	.has_gamma_table	=	true,
446662306a36Sopenharmony_ci	.has_gamma_i734_bug	=	true,
446762306a36Sopenharmony_ci};
446862306a36Sopenharmony_ci
446962306a36Sopenharmony_cistatic const struct dispc_features omap54xx_dispc_feats = {
447062306a36Sopenharmony_ci	.sw_start		=	7,
447162306a36Sopenharmony_ci	.fp_start		=	19,
447262306a36Sopenharmony_ci	.bp_start		=	31,
447362306a36Sopenharmony_ci	.sw_max			=	256,
447462306a36Sopenharmony_ci	.vp_max			=	4095,
447562306a36Sopenharmony_ci	.hp_max			=	4096,
447662306a36Sopenharmony_ci	.mgr_width_start	=	11,
447762306a36Sopenharmony_ci	.mgr_height_start	=	27,
447862306a36Sopenharmony_ci	.mgr_width_max		=	4096,
447962306a36Sopenharmony_ci	.mgr_height_max		=	4096,
448062306a36Sopenharmony_ci	.ovl_width_max		=	2048,
448162306a36Sopenharmony_ci	.ovl_height_max		=	4096,
448262306a36Sopenharmony_ci	.max_lcd_pclk		=	170000000,
448362306a36Sopenharmony_ci	.max_tv_pclk		=	192000000,
448462306a36Sopenharmony_ci	.max_downscale		=	4,
448562306a36Sopenharmony_ci	.max_line_width		=	2048,
448662306a36Sopenharmony_ci	.min_pcd		=	1,
448762306a36Sopenharmony_ci	.calc_scaling		=	dispc_ovl_calc_scaling_44xx,
448862306a36Sopenharmony_ci	.calc_core_clk		=	calc_core_clk_44xx,
448962306a36Sopenharmony_ci	.num_fifos		=	5,
449062306a36Sopenharmony_ci	.features		=	omap5_dispc_features_list,
449162306a36Sopenharmony_ci	.num_features		=	ARRAY_SIZE(omap5_dispc_features_list),
449262306a36Sopenharmony_ci	.reg_fields		=	omap4_dispc_reg_fields,
449362306a36Sopenharmony_ci	.num_reg_fields		=	ARRAY_SIZE(omap4_dispc_reg_fields),
449462306a36Sopenharmony_ci	.overlay_caps		=	omap4_dispc_overlay_caps,
449562306a36Sopenharmony_ci	.supported_color_modes	=	omap4_dispc_supported_color_modes,
449662306a36Sopenharmony_ci	.num_mgrs		=	4,
449762306a36Sopenharmony_ci	.num_ovls		=	4,
449862306a36Sopenharmony_ci	.buffer_size_unit	=	16,
449962306a36Sopenharmony_ci	.burst_size_unit	=	16,
450062306a36Sopenharmony_ci	.gfx_fifo_workaround	=	true,
450162306a36Sopenharmony_ci	.mstandby_workaround	=	true,
450262306a36Sopenharmony_ci	.set_max_preload	=	true,
450362306a36Sopenharmony_ci	.supports_sync_align	=	true,
450462306a36Sopenharmony_ci	.has_writeback		=	true,
450562306a36Sopenharmony_ci	.supports_double_pixel	=	true,
450662306a36Sopenharmony_ci	.reverse_ilace_field_order =	true,
450762306a36Sopenharmony_ci	.has_gamma_table	=	true,
450862306a36Sopenharmony_ci	.has_gamma_i734_bug	=	true,
450962306a36Sopenharmony_ci};
451062306a36Sopenharmony_ci
451162306a36Sopenharmony_cistatic irqreturn_t dispc_irq_handler(int irq, void *arg)
451262306a36Sopenharmony_ci{
451362306a36Sopenharmony_ci	struct dispc_device *dispc = arg;
451462306a36Sopenharmony_ci
451562306a36Sopenharmony_ci	if (!dispc->is_enabled)
451662306a36Sopenharmony_ci		return IRQ_NONE;
451762306a36Sopenharmony_ci
451862306a36Sopenharmony_ci	return dispc->user_handler(irq, dispc->user_data);
451962306a36Sopenharmony_ci}
452062306a36Sopenharmony_ci
452162306a36Sopenharmony_ciint dispc_request_irq(struct dispc_device *dispc, irq_handler_t handler,
452262306a36Sopenharmony_ci			     void *dev_id)
452362306a36Sopenharmony_ci{
452462306a36Sopenharmony_ci	int r;
452562306a36Sopenharmony_ci
452662306a36Sopenharmony_ci	if (dispc->user_handler != NULL)
452762306a36Sopenharmony_ci		return -EBUSY;
452862306a36Sopenharmony_ci
452962306a36Sopenharmony_ci	dispc->user_handler = handler;
453062306a36Sopenharmony_ci	dispc->user_data = dev_id;
453162306a36Sopenharmony_ci
453262306a36Sopenharmony_ci	/* ensure the dispc_irq_handler sees the values above */
453362306a36Sopenharmony_ci	smp_wmb();
453462306a36Sopenharmony_ci
453562306a36Sopenharmony_ci	r = devm_request_irq(&dispc->pdev->dev, dispc->irq, dispc_irq_handler,
453662306a36Sopenharmony_ci			     IRQF_SHARED, "OMAP DISPC", dispc);
453762306a36Sopenharmony_ci	if (r) {
453862306a36Sopenharmony_ci		dispc->user_handler = NULL;
453962306a36Sopenharmony_ci		dispc->user_data = NULL;
454062306a36Sopenharmony_ci	}
454162306a36Sopenharmony_ci
454262306a36Sopenharmony_ci	return r;
454362306a36Sopenharmony_ci}
454462306a36Sopenharmony_ci
454562306a36Sopenharmony_civoid dispc_free_irq(struct dispc_device *dispc, void *dev_id)
454662306a36Sopenharmony_ci{
454762306a36Sopenharmony_ci	devm_free_irq(&dispc->pdev->dev, dispc->irq, dispc);
454862306a36Sopenharmony_ci
454962306a36Sopenharmony_ci	dispc->user_handler = NULL;
455062306a36Sopenharmony_ci	dispc->user_data = NULL;
455162306a36Sopenharmony_ci}
455262306a36Sopenharmony_ci
455362306a36Sopenharmony_ciu32 dispc_get_memory_bandwidth_limit(struct dispc_device *dispc)
455462306a36Sopenharmony_ci{
455562306a36Sopenharmony_ci	u32 limit = 0;
455662306a36Sopenharmony_ci
455762306a36Sopenharmony_ci	/* Optional maximum memory bandwidth */
455862306a36Sopenharmony_ci	of_property_read_u32(dispc->pdev->dev.of_node, "max-memory-bandwidth",
455962306a36Sopenharmony_ci			     &limit);
456062306a36Sopenharmony_ci
456162306a36Sopenharmony_ci	return limit;
456262306a36Sopenharmony_ci}
456362306a36Sopenharmony_ci
456462306a36Sopenharmony_ci/*
456562306a36Sopenharmony_ci * Workaround for errata i734 in DSS dispc
456662306a36Sopenharmony_ci *  - LCD1 Gamma Correction Is Not Working When GFX Pipe Is Disabled
456762306a36Sopenharmony_ci *
456862306a36Sopenharmony_ci * For gamma tables to work on LCD1 the GFX plane has to be used at
456962306a36Sopenharmony_ci * least once after DSS HW has come out of reset. The workaround
457062306a36Sopenharmony_ci * sets up a minimal LCD setup with GFX plane and waits for one
457162306a36Sopenharmony_ci * vertical sync irq before disabling the setup and continuing with
457262306a36Sopenharmony_ci * the context restore. The physical outputs are gated during the
457362306a36Sopenharmony_ci * operation. This workaround requires that gamma table's LOADMODE
457462306a36Sopenharmony_ci * is set to 0x2 in DISPC_CONTROL1 register.
457562306a36Sopenharmony_ci *
457662306a36Sopenharmony_ci * For details see:
457762306a36Sopenharmony_ci * OMAP543x Multimedia Device Silicon Revision 2.0 Silicon Errata
457862306a36Sopenharmony_ci * Literature Number: SWPZ037E
457962306a36Sopenharmony_ci * Or some other relevant errata document for the DSS IP version.
458062306a36Sopenharmony_ci */
458162306a36Sopenharmony_ci
458262306a36Sopenharmony_cistatic const struct dispc_errata_i734_data {
458362306a36Sopenharmony_ci	struct videomode vm;
458462306a36Sopenharmony_ci	struct omap_overlay_info ovli;
458562306a36Sopenharmony_ci	struct omap_overlay_manager_info mgri;
458662306a36Sopenharmony_ci	struct dss_lcd_mgr_config lcd_conf;
458762306a36Sopenharmony_ci} i734 = {
458862306a36Sopenharmony_ci	.vm = {
458962306a36Sopenharmony_ci		.hactive = 8, .vactive = 1,
459062306a36Sopenharmony_ci		.pixelclock = 16000000,
459162306a36Sopenharmony_ci		.hsync_len = 8, .hfront_porch = 4, .hback_porch = 4,
459262306a36Sopenharmony_ci		.vsync_len = 1, .vfront_porch = 1, .vback_porch = 1,
459362306a36Sopenharmony_ci
459462306a36Sopenharmony_ci		.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
459562306a36Sopenharmony_ci			 DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_POSEDGE |
459662306a36Sopenharmony_ci			 DISPLAY_FLAGS_PIXDATA_POSEDGE,
459762306a36Sopenharmony_ci	},
459862306a36Sopenharmony_ci	.ovli = {
459962306a36Sopenharmony_ci		.screen_width = 1,
460062306a36Sopenharmony_ci		.width = 1, .height = 1,
460162306a36Sopenharmony_ci		.fourcc = DRM_FORMAT_XRGB8888,
460262306a36Sopenharmony_ci		.rotation = DRM_MODE_ROTATE_0,
460362306a36Sopenharmony_ci		.rotation_type = OMAP_DSS_ROT_NONE,
460462306a36Sopenharmony_ci		.pos_x = 0, .pos_y = 0,
460562306a36Sopenharmony_ci		.out_width = 0, .out_height = 0,
460662306a36Sopenharmony_ci		.global_alpha = 0xff,
460762306a36Sopenharmony_ci		.pre_mult_alpha = 0,
460862306a36Sopenharmony_ci		.zorder = 0,
460962306a36Sopenharmony_ci	},
461062306a36Sopenharmony_ci	.mgri = {
461162306a36Sopenharmony_ci		.default_color = 0,
461262306a36Sopenharmony_ci		.trans_enabled = false,
461362306a36Sopenharmony_ci		.partial_alpha_enabled = false,
461462306a36Sopenharmony_ci		.cpr_enable = false,
461562306a36Sopenharmony_ci	},
461662306a36Sopenharmony_ci	.lcd_conf = {
461762306a36Sopenharmony_ci		.io_pad_mode = DSS_IO_PAD_MODE_BYPASS,
461862306a36Sopenharmony_ci		.stallmode = false,
461962306a36Sopenharmony_ci		.fifohandcheck = false,
462062306a36Sopenharmony_ci		.clock_info = {
462162306a36Sopenharmony_ci			.lck_div = 1,
462262306a36Sopenharmony_ci			.pck_div = 2,
462362306a36Sopenharmony_ci		},
462462306a36Sopenharmony_ci		.video_port_width = 24,
462562306a36Sopenharmony_ci		.lcden_sig_polarity = 0,
462662306a36Sopenharmony_ci	},
462762306a36Sopenharmony_ci};
462862306a36Sopenharmony_ci
462962306a36Sopenharmony_cistatic struct i734_buf {
463062306a36Sopenharmony_ci	size_t size;
463162306a36Sopenharmony_ci	dma_addr_t paddr;
463262306a36Sopenharmony_ci	void *vaddr;
463362306a36Sopenharmony_ci} i734_buf;
463462306a36Sopenharmony_ci
463562306a36Sopenharmony_cistatic int dispc_errata_i734_wa_init(struct dispc_device *dispc)
463662306a36Sopenharmony_ci{
463762306a36Sopenharmony_ci	if (!dispc->feat->has_gamma_i734_bug)
463862306a36Sopenharmony_ci		return 0;
463962306a36Sopenharmony_ci
464062306a36Sopenharmony_ci	i734_buf.size = i734.ovli.width * i734.ovli.height *
464162306a36Sopenharmony_ci		color_mode_to_bpp(i734.ovli.fourcc) / 8;
464262306a36Sopenharmony_ci
464362306a36Sopenharmony_ci	i734_buf.vaddr = dma_alloc_wc(&dispc->pdev->dev, i734_buf.size,
464462306a36Sopenharmony_ci				      &i734_buf.paddr, GFP_KERNEL);
464562306a36Sopenharmony_ci	if (!i734_buf.vaddr) {
464662306a36Sopenharmony_ci		dev_err(&dispc->pdev->dev, "%s: dma_alloc_wc failed\n",
464762306a36Sopenharmony_ci			__func__);
464862306a36Sopenharmony_ci		return -ENOMEM;
464962306a36Sopenharmony_ci	}
465062306a36Sopenharmony_ci
465162306a36Sopenharmony_ci	return 0;
465262306a36Sopenharmony_ci}
465362306a36Sopenharmony_ci
465462306a36Sopenharmony_cistatic void dispc_errata_i734_wa_fini(struct dispc_device *dispc)
465562306a36Sopenharmony_ci{
465662306a36Sopenharmony_ci	if (!dispc->feat->has_gamma_i734_bug)
465762306a36Sopenharmony_ci		return;
465862306a36Sopenharmony_ci
465962306a36Sopenharmony_ci	dma_free_wc(&dispc->pdev->dev, i734_buf.size, i734_buf.vaddr,
466062306a36Sopenharmony_ci		    i734_buf.paddr);
466162306a36Sopenharmony_ci}
466262306a36Sopenharmony_ci
466362306a36Sopenharmony_cistatic void dispc_errata_i734_wa(struct dispc_device *dispc)
466462306a36Sopenharmony_ci{
466562306a36Sopenharmony_ci	u32 framedone_irq = dispc_mgr_get_framedone_irq(dispc,
466662306a36Sopenharmony_ci							OMAP_DSS_CHANNEL_LCD);
466762306a36Sopenharmony_ci	struct omap_overlay_info ovli;
466862306a36Sopenharmony_ci	struct dss_lcd_mgr_config lcd_conf;
466962306a36Sopenharmony_ci	u32 gatestate;
467062306a36Sopenharmony_ci	unsigned int count;
467162306a36Sopenharmony_ci
467262306a36Sopenharmony_ci	if (!dispc->feat->has_gamma_i734_bug)
467362306a36Sopenharmony_ci		return;
467462306a36Sopenharmony_ci
467562306a36Sopenharmony_ci	gatestate = REG_GET(dispc, DISPC_CONFIG, 8, 4);
467662306a36Sopenharmony_ci
467762306a36Sopenharmony_ci	ovli = i734.ovli;
467862306a36Sopenharmony_ci	ovli.paddr = i734_buf.paddr;
467962306a36Sopenharmony_ci	lcd_conf = i734.lcd_conf;
468062306a36Sopenharmony_ci
468162306a36Sopenharmony_ci	/* Gate all LCD1 outputs */
468262306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_CONFIG, 0x1f, 8, 4);
468362306a36Sopenharmony_ci
468462306a36Sopenharmony_ci	/* Setup and enable GFX plane */
468562306a36Sopenharmony_ci	dispc_ovl_setup(dispc, OMAP_DSS_GFX, &ovli, &i734.vm, false,
468662306a36Sopenharmony_ci			OMAP_DSS_CHANNEL_LCD);
468762306a36Sopenharmony_ci	dispc_ovl_enable(dispc, OMAP_DSS_GFX, true);
468862306a36Sopenharmony_ci
468962306a36Sopenharmony_ci	/* Set up and enable display manager for LCD1 */
469062306a36Sopenharmony_ci	dispc_mgr_setup(dispc, OMAP_DSS_CHANNEL_LCD, &i734.mgri);
469162306a36Sopenharmony_ci	dispc_calc_clock_rates(dispc, dss_get_dispc_clk_rate(dispc->dss),
469262306a36Sopenharmony_ci			       &lcd_conf.clock_info);
469362306a36Sopenharmony_ci	dispc_mgr_set_lcd_config(dispc, OMAP_DSS_CHANNEL_LCD, &lcd_conf);
469462306a36Sopenharmony_ci	dispc_mgr_set_timings(dispc, OMAP_DSS_CHANNEL_LCD, &i734.vm);
469562306a36Sopenharmony_ci
469662306a36Sopenharmony_ci	dispc_clear_irqstatus(dispc, framedone_irq);
469762306a36Sopenharmony_ci
469862306a36Sopenharmony_ci	/* Enable and shut the channel to produce just one frame */
469962306a36Sopenharmony_ci	dispc_mgr_enable(dispc, OMAP_DSS_CHANNEL_LCD, true);
470062306a36Sopenharmony_ci	dispc_mgr_enable(dispc, OMAP_DSS_CHANNEL_LCD, false);
470162306a36Sopenharmony_ci
470262306a36Sopenharmony_ci	/* Busy wait for framedone. We can't fiddle with irq handlers
470362306a36Sopenharmony_ci	 * in PM resume. Typically the loop runs less than 5 times and
470462306a36Sopenharmony_ci	 * waits less than a micro second.
470562306a36Sopenharmony_ci	 */
470662306a36Sopenharmony_ci	count = 0;
470762306a36Sopenharmony_ci	while (!(dispc_read_irqstatus(dispc) & framedone_irq)) {
470862306a36Sopenharmony_ci		if (count++ > 10000) {
470962306a36Sopenharmony_ci			dev_err(&dispc->pdev->dev, "%s: framedone timeout\n",
471062306a36Sopenharmony_ci				__func__);
471162306a36Sopenharmony_ci			break;
471262306a36Sopenharmony_ci		}
471362306a36Sopenharmony_ci	}
471462306a36Sopenharmony_ci	dispc_ovl_enable(dispc, OMAP_DSS_GFX, false);
471562306a36Sopenharmony_ci
471662306a36Sopenharmony_ci	/* Clear all irq bits before continuing */
471762306a36Sopenharmony_ci	dispc_clear_irqstatus(dispc, 0xffffffff);
471862306a36Sopenharmony_ci
471962306a36Sopenharmony_ci	/* Restore the original state to LCD1 output gates */
472062306a36Sopenharmony_ci	REG_FLD_MOD(dispc, DISPC_CONFIG, gatestate, 8, 4);
472162306a36Sopenharmony_ci}
472262306a36Sopenharmony_ci
472362306a36Sopenharmony_ci/* DISPC HW IP initialisation */
472462306a36Sopenharmony_cistatic const struct of_device_id dispc_of_match[] = {
472562306a36Sopenharmony_ci	{ .compatible = "ti,omap2-dispc", .data = &omap24xx_dispc_feats },
472662306a36Sopenharmony_ci	{ .compatible = "ti,omap3-dispc", .data = &omap36xx_dispc_feats },
472762306a36Sopenharmony_ci	{ .compatible = "ti,omap4-dispc", .data = &omap44xx_dispc_feats },
472862306a36Sopenharmony_ci	{ .compatible = "ti,omap5-dispc", .data = &omap54xx_dispc_feats },
472962306a36Sopenharmony_ci	{ .compatible = "ti,dra7-dispc",  .data = &omap54xx_dispc_feats },
473062306a36Sopenharmony_ci	{},
473162306a36Sopenharmony_ci};
473262306a36Sopenharmony_ci
473362306a36Sopenharmony_cistatic const struct soc_device_attribute dispc_soc_devices[] = {
473462306a36Sopenharmony_ci	{ .machine = "OMAP3[45]*",
473562306a36Sopenharmony_ci	  .revision = "ES[12].?",	.data = &omap34xx_rev1_0_dispc_feats },
473662306a36Sopenharmony_ci	{ .machine = "OMAP3[45]*",	.data = &omap34xx_rev3_0_dispc_feats },
473762306a36Sopenharmony_ci	{ .machine = "AM35*",		.data = &omap34xx_rev3_0_dispc_feats },
473862306a36Sopenharmony_ci	{ .machine = "AM43*",		.data = &am43xx_dispc_feats },
473962306a36Sopenharmony_ci	{ /* sentinel */ }
474062306a36Sopenharmony_ci};
474162306a36Sopenharmony_ci
474262306a36Sopenharmony_cistatic int dispc_bind(struct device *dev, struct device *master, void *data)
474362306a36Sopenharmony_ci{
474462306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
474562306a36Sopenharmony_ci	const struct soc_device_attribute *soc;
474662306a36Sopenharmony_ci	struct dss_device *dss = dss_get_device(master);
474762306a36Sopenharmony_ci	struct dispc_device *dispc;
474862306a36Sopenharmony_ci	u32 rev;
474962306a36Sopenharmony_ci	int r = 0;
475062306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
475162306a36Sopenharmony_ci
475262306a36Sopenharmony_ci	dispc = kzalloc(sizeof(*dispc), GFP_KERNEL);
475362306a36Sopenharmony_ci	if (!dispc)
475462306a36Sopenharmony_ci		return -ENOMEM;
475562306a36Sopenharmony_ci
475662306a36Sopenharmony_ci	dispc->pdev = pdev;
475762306a36Sopenharmony_ci	platform_set_drvdata(pdev, dispc);
475862306a36Sopenharmony_ci	dispc->dss = dss;
475962306a36Sopenharmony_ci
476062306a36Sopenharmony_ci	/*
476162306a36Sopenharmony_ci	 * The OMAP3-based models can't be told apart using the compatible
476262306a36Sopenharmony_ci	 * string, use SoC device matching.
476362306a36Sopenharmony_ci	 */
476462306a36Sopenharmony_ci	soc = soc_device_match(dispc_soc_devices);
476562306a36Sopenharmony_ci	if (soc)
476662306a36Sopenharmony_ci		dispc->feat = soc->data;
476762306a36Sopenharmony_ci	else
476862306a36Sopenharmony_ci		dispc->feat = of_match_device(dispc_of_match, &pdev->dev)->data;
476962306a36Sopenharmony_ci
477062306a36Sopenharmony_ci	r = dispc_errata_i734_wa_init(dispc);
477162306a36Sopenharmony_ci	if (r)
477262306a36Sopenharmony_ci		goto err_free;
477362306a36Sopenharmony_ci
477462306a36Sopenharmony_ci	dispc->base = devm_platform_ioremap_resource(pdev, 0);
477562306a36Sopenharmony_ci	if (IS_ERR(dispc->base)) {
477662306a36Sopenharmony_ci		r = PTR_ERR(dispc->base);
477762306a36Sopenharmony_ci		goto err_free;
477862306a36Sopenharmony_ci	}
477962306a36Sopenharmony_ci
478062306a36Sopenharmony_ci	dispc->irq = platform_get_irq(dispc->pdev, 0);
478162306a36Sopenharmony_ci	if (dispc->irq < 0) {
478262306a36Sopenharmony_ci		DSSERR("platform_get_irq failed\n");
478362306a36Sopenharmony_ci		r = -ENODEV;
478462306a36Sopenharmony_ci		goto err_free;
478562306a36Sopenharmony_ci	}
478662306a36Sopenharmony_ci
478762306a36Sopenharmony_ci	if (np && of_property_read_bool(np, "syscon-pol")) {
478862306a36Sopenharmony_ci		dispc->syscon_pol = syscon_regmap_lookup_by_phandle(np, "syscon-pol");
478962306a36Sopenharmony_ci		if (IS_ERR(dispc->syscon_pol)) {
479062306a36Sopenharmony_ci			dev_err(&pdev->dev, "failed to get syscon-pol regmap\n");
479162306a36Sopenharmony_ci			r = PTR_ERR(dispc->syscon_pol);
479262306a36Sopenharmony_ci			goto err_free;
479362306a36Sopenharmony_ci		}
479462306a36Sopenharmony_ci
479562306a36Sopenharmony_ci		if (of_property_read_u32_index(np, "syscon-pol", 1,
479662306a36Sopenharmony_ci				&dispc->syscon_pol_offset)) {
479762306a36Sopenharmony_ci			dev_err(&pdev->dev, "failed to get syscon-pol offset\n");
479862306a36Sopenharmony_ci			r = -EINVAL;
479962306a36Sopenharmony_ci			goto err_free;
480062306a36Sopenharmony_ci		}
480162306a36Sopenharmony_ci	}
480262306a36Sopenharmony_ci
480362306a36Sopenharmony_ci	r = dispc_init_gamma_tables(dispc);
480462306a36Sopenharmony_ci	if (r)
480562306a36Sopenharmony_ci		goto err_free;
480662306a36Sopenharmony_ci
480762306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
480862306a36Sopenharmony_ci
480962306a36Sopenharmony_ci	r = dispc_runtime_get(dispc);
481062306a36Sopenharmony_ci	if (r)
481162306a36Sopenharmony_ci		goto err_runtime_get;
481262306a36Sopenharmony_ci
481362306a36Sopenharmony_ci	_omap_dispc_initial_config(dispc);
481462306a36Sopenharmony_ci
481562306a36Sopenharmony_ci	rev = dispc_read_reg(dispc, DISPC_REVISION);
481662306a36Sopenharmony_ci	dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
481762306a36Sopenharmony_ci	       FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
481862306a36Sopenharmony_ci
481962306a36Sopenharmony_ci	dispc_runtime_put(dispc);
482062306a36Sopenharmony_ci
482162306a36Sopenharmony_ci	dss->dispc = dispc;
482262306a36Sopenharmony_ci
482362306a36Sopenharmony_ci	dispc->debugfs = dss_debugfs_create_file(dss, "dispc", dispc_dump_regs,
482462306a36Sopenharmony_ci						 dispc);
482562306a36Sopenharmony_ci
482662306a36Sopenharmony_ci	return 0;
482762306a36Sopenharmony_ci
482862306a36Sopenharmony_cierr_runtime_get:
482962306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
483062306a36Sopenharmony_cierr_free:
483162306a36Sopenharmony_ci	kfree(dispc);
483262306a36Sopenharmony_ci	return r;
483362306a36Sopenharmony_ci}
483462306a36Sopenharmony_ci
483562306a36Sopenharmony_cistatic void dispc_unbind(struct device *dev, struct device *master, void *data)
483662306a36Sopenharmony_ci{
483762306a36Sopenharmony_ci	struct dispc_device *dispc = dev_get_drvdata(dev);
483862306a36Sopenharmony_ci	struct dss_device *dss = dispc->dss;
483962306a36Sopenharmony_ci
484062306a36Sopenharmony_ci	dss_debugfs_remove_file(dispc->debugfs);
484162306a36Sopenharmony_ci
484262306a36Sopenharmony_ci	dss->dispc = NULL;
484362306a36Sopenharmony_ci
484462306a36Sopenharmony_ci	pm_runtime_disable(dev);
484562306a36Sopenharmony_ci
484662306a36Sopenharmony_ci	dispc_errata_i734_wa_fini(dispc);
484762306a36Sopenharmony_ci
484862306a36Sopenharmony_ci	kfree(dispc);
484962306a36Sopenharmony_ci}
485062306a36Sopenharmony_ci
485162306a36Sopenharmony_cistatic const struct component_ops dispc_component_ops = {
485262306a36Sopenharmony_ci	.bind	= dispc_bind,
485362306a36Sopenharmony_ci	.unbind	= dispc_unbind,
485462306a36Sopenharmony_ci};
485562306a36Sopenharmony_ci
485662306a36Sopenharmony_cistatic int dispc_probe(struct platform_device *pdev)
485762306a36Sopenharmony_ci{
485862306a36Sopenharmony_ci	return component_add(&pdev->dev, &dispc_component_ops);
485962306a36Sopenharmony_ci}
486062306a36Sopenharmony_ci
486162306a36Sopenharmony_cistatic void dispc_remove(struct platform_device *pdev)
486262306a36Sopenharmony_ci{
486362306a36Sopenharmony_ci	component_del(&pdev->dev, &dispc_component_ops);
486462306a36Sopenharmony_ci}
486562306a36Sopenharmony_ci
486662306a36Sopenharmony_cistatic __maybe_unused int dispc_runtime_suspend(struct device *dev)
486762306a36Sopenharmony_ci{
486862306a36Sopenharmony_ci	struct dispc_device *dispc = dev_get_drvdata(dev);
486962306a36Sopenharmony_ci
487062306a36Sopenharmony_ci	dispc->is_enabled = false;
487162306a36Sopenharmony_ci	/* ensure the dispc_irq_handler sees the is_enabled value */
487262306a36Sopenharmony_ci	smp_wmb();
487362306a36Sopenharmony_ci	/* wait for current handler to finish before turning the DISPC off */
487462306a36Sopenharmony_ci	synchronize_irq(dispc->irq);
487562306a36Sopenharmony_ci
487662306a36Sopenharmony_ci	dispc_save_context(dispc);
487762306a36Sopenharmony_ci
487862306a36Sopenharmony_ci	return 0;
487962306a36Sopenharmony_ci}
488062306a36Sopenharmony_ci
488162306a36Sopenharmony_cistatic __maybe_unused int dispc_runtime_resume(struct device *dev)
488262306a36Sopenharmony_ci{
488362306a36Sopenharmony_ci	struct dispc_device *dispc = dev_get_drvdata(dev);
488462306a36Sopenharmony_ci
488562306a36Sopenharmony_ci	/*
488662306a36Sopenharmony_ci	 * The reset value for load mode is 0 (OMAP_DSS_LOAD_CLUT_AND_FRAME)
488762306a36Sopenharmony_ci	 * but we always initialize it to 2 (OMAP_DSS_LOAD_FRAME_ONLY) in
488862306a36Sopenharmony_ci	 * _omap_dispc_initial_config(). We can thus use it to detect if
488962306a36Sopenharmony_ci	 * we have lost register context.
489062306a36Sopenharmony_ci	 */
489162306a36Sopenharmony_ci	if (REG_GET(dispc, DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) {
489262306a36Sopenharmony_ci		_omap_dispc_initial_config(dispc);
489362306a36Sopenharmony_ci
489462306a36Sopenharmony_ci		dispc_errata_i734_wa(dispc);
489562306a36Sopenharmony_ci
489662306a36Sopenharmony_ci		dispc_restore_context(dispc);
489762306a36Sopenharmony_ci
489862306a36Sopenharmony_ci		dispc_restore_gamma_tables(dispc);
489962306a36Sopenharmony_ci	}
490062306a36Sopenharmony_ci
490162306a36Sopenharmony_ci	dispc->is_enabled = true;
490262306a36Sopenharmony_ci	/* ensure the dispc_irq_handler sees the is_enabled value */
490362306a36Sopenharmony_ci	smp_wmb();
490462306a36Sopenharmony_ci
490562306a36Sopenharmony_ci	return 0;
490662306a36Sopenharmony_ci}
490762306a36Sopenharmony_ci
490862306a36Sopenharmony_cistatic const struct dev_pm_ops dispc_pm_ops = {
490962306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(dispc_runtime_suspend, dispc_runtime_resume, NULL)
491062306a36Sopenharmony_ci	SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
491162306a36Sopenharmony_ci};
491262306a36Sopenharmony_ci
491362306a36Sopenharmony_cistruct platform_driver omap_dispchw_driver = {
491462306a36Sopenharmony_ci	.probe		= dispc_probe,
491562306a36Sopenharmony_ci	.remove_new     = dispc_remove,
491662306a36Sopenharmony_ci	.driver         = {
491762306a36Sopenharmony_ci		.name   = "omapdss_dispc",
491862306a36Sopenharmony_ci		.pm	= &dispc_pm_ops,
491962306a36Sopenharmony_ci		.of_match_table = dispc_of_match,
492062306a36Sopenharmony_ci		.suppress_bind_attrs = true,
492162306a36Sopenharmony_ci	},
492262306a36Sopenharmony_ci};
4923