cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dispc.c (131345B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2009 Nokia Corporation
      4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
      5 *
      6 * Some code and ideas taken from drivers/video/omap/ driver
      7 * by Imre Deak.
      8 */
      9
     10#define DSS_SUBSYS_NAME "DISPC"
     11
     12#include <linux/kernel.h>
     13#include <linux/dma-mapping.h>
     14#include <linux/vmalloc.h>
     15#include <linux/export.h>
     16#include <linux/clk.h>
     17#include <linux/io.h>
     18#include <linux/jiffies.h>
     19#include <linux/seq_file.h>
     20#include <linux/delay.h>
     21#include <linux/workqueue.h>
     22#include <linux/hardirq.h>
     23#include <linux/platform_device.h>
     24#include <linux/pm_runtime.h>
     25#include <linux/sizes.h>
     26#include <linux/mfd/syscon.h>
     27#include <linux/regmap.h>
     28#include <linux/of.h>
     29#include <linux/of_device.h>
     30#include <linux/component.h>
     31#include <linux/sys_soc.h>
     32#include <drm/drm_fourcc.h>
     33#include <drm/drm_blend.h>
     34
     35#include "omapdss.h"
     36#include "dss.h"
     37#include "dispc.h"
     38
     39struct dispc_device;
     40
     41/* DISPC */
     42#define DISPC_SZ_REGS			SZ_4K
     43
     44enum omap_burst_size {
     45	BURST_SIZE_X2 = 0,
     46	BURST_SIZE_X4 = 1,
     47	BURST_SIZE_X8 = 2,
     48};
     49
     50#define REG_GET(dispc, idx, start, end) \
     51	FLD_GET(dispc_read_reg(dispc, idx), start, end)
     52
     53#define REG_FLD_MOD(dispc, idx, val, start, end)			\
     54	dispc_write_reg(dispc, idx, \
     55			FLD_MOD(dispc_read_reg(dispc, idx), val, start, end))
     56
     57/* DISPC has feature id */
     58enum dispc_feature_id {
     59	FEAT_LCDENABLEPOL,
     60	FEAT_LCDENABLESIGNAL,
     61	FEAT_PCKFREEENABLE,
     62	FEAT_FUNCGATED,
     63	FEAT_MGR_LCD2,
     64	FEAT_MGR_LCD3,
     65	FEAT_LINEBUFFERSPLIT,
     66	FEAT_ROWREPEATENABLE,
     67	FEAT_RESIZECONF,
     68	/* Independent core clk divider */
     69	FEAT_CORE_CLK_DIV,
     70	FEAT_HANDLE_UV_SEPARATE,
     71	FEAT_ATTR2,
     72	FEAT_CPR,
     73	FEAT_PRELOAD,
     74	FEAT_FIR_COEF_V,
     75	FEAT_ALPHA_FIXED_ZORDER,
     76	FEAT_ALPHA_FREE_ZORDER,
     77	FEAT_FIFO_MERGE,
     78	/* An unknown HW bug causing the normal FIFO thresholds not to work */
     79	FEAT_OMAP3_DSI_FIFO_BUG,
     80	FEAT_BURST_2D,
     81	FEAT_MFLAG,
     82};
     83
     84struct dispc_features {
     85	u8 sw_start;
     86	u8 fp_start;
     87	u8 bp_start;
     88	u16 sw_max;
     89	u16 vp_max;
     90	u16 hp_max;
     91	u8 mgr_width_start;
     92	u8 mgr_height_start;
     93	u16 mgr_width_max;
     94	u16 mgr_height_max;
     95	u16 ovl_width_max;
     96	u16 ovl_height_max;
     97	unsigned long max_lcd_pclk;
     98	unsigned long max_tv_pclk;
     99	unsigned int max_downscale;
    100	unsigned int max_line_width;
    101	unsigned int min_pcd;
    102	int (*calc_scaling)(struct dispc_device *dispc,
    103		unsigned long pclk, unsigned long lclk,
    104		const struct videomode *vm,
    105		u16 width, u16 height, u16 out_width, u16 out_height,
    106		u32 fourcc, bool *five_taps,
    107		int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
    108		u16 pos_x, unsigned long *core_clk, bool mem_to_mem);
    109	unsigned long (*calc_core_clk) (unsigned long pclk,
    110		u16 width, u16 height, u16 out_width, u16 out_height,
    111		bool mem_to_mem);
    112	u8 num_fifos;
    113	const enum dispc_feature_id *features;
    114	unsigned int num_features;
    115	const struct dss_reg_field *reg_fields;
    116	const unsigned int num_reg_fields;
    117	const enum omap_overlay_caps *overlay_caps;
    118	const u32 **supported_color_modes;
    119	const u32 *supported_scaler_color_modes;
    120	unsigned int num_mgrs;
    121	unsigned int num_ovls;
    122	unsigned int buffer_size_unit;
    123	unsigned int burst_size_unit;
    124
    125	/* swap GFX & WB fifos */
    126	bool gfx_fifo_workaround:1;
    127
    128	/* no DISPC_IRQ_FRAMEDONETV on this SoC */
    129	bool no_framedone_tv:1;
    130
    131	/* revert to the OMAP4 mechanism of DISPC Smart Standby operation */
    132	bool mstandby_workaround:1;
    133
    134	bool set_max_preload:1;
    135
    136	/* PIXEL_INC is not added to the last pixel of a line */
    137	bool last_pixel_inc_missing:1;
    138
    139	/* POL_FREQ has ALIGN bit */
    140	bool supports_sync_align:1;
    141
    142	bool has_writeback:1;
    143
    144	bool supports_double_pixel:1;
    145
    146	/*
    147	 * Field order for VENC is different than HDMI. We should handle this in
    148	 * some intelligent manner, but as the SoCs have either HDMI or VENC,
    149	 * never both, we can just use this flag for now.
    150	 */
    151	bool reverse_ilace_field_order:1;
    152
    153	bool has_gamma_table:1;
    154
    155	bool has_gamma_i734_bug:1;
    156};
    157
    158#define DISPC_MAX_NR_FIFOS 5
    159#define DISPC_MAX_CHANNEL_GAMMA 4
    160
    161struct dispc_device {
    162	struct platform_device *pdev;
    163	void __iomem    *base;
    164	struct dss_device *dss;
    165
    166	struct dss_debugfs_entry *debugfs;
    167
    168	int irq;
    169	irq_handler_t user_handler;
    170	void *user_data;
    171
    172	unsigned long core_clk_rate;
    173	unsigned long tv_pclk_rate;
    174
    175	u32 fifo_size[DISPC_MAX_NR_FIFOS];
    176	/* maps which plane is using a fifo. fifo-id -> plane-id */
    177	int fifo_assignment[DISPC_MAX_NR_FIFOS];
    178
    179	bool		ctx_valid;
    180	u32		ctx[DISPC_SZ_REGS / sizeof(u32)];
    181
    182	u32 *gamma_table[DISPC_MAX_CHANNEL_GAMMA];
    183
    184	const struct dispc_features *feat;
    185
    186	bool is_enabled;
    187
    188	struct regmap *syscon_pol;
    189	u32 syscon_pol_offset;
    190};
    191
    192enum omap_color_component {
    193	/* used for all color formats for OMAP3 and earlier
    194	 * and for RGB and Y color component on OMAP4
    195	 */
    196	DISPC_COLOR_COMPONENT_RGB_Y		= 1 << 0,
    197	/* used for UV component for
    198	 * DRM_FORMAT_YUYV, DRM_FORMAT_UYVY, DRM_FORMAT_NV12
    199	 * color formats on OMAP4
    200	 */
    201	DISPC_COLOR_COMPONENT_UV		= 1 << 1,
    202};
    203
    204enum mgr_reg_fields {
    205	DISPC_MGR_FLD_ENABLE,
    206	DISPC_MGR_FLD_STNTFT,
    207	DISPC_MGR_FLD_GO,
    208	DISPC_MGR_FLD_TFTDATALINES,
    209	DISPC_MGR_FLD_STALLMODE,
    210	DISPC_MGR_FLD_TCKENABLE,
    211	DISPC_MGR_FLD_TCKSELECTION,
    212	DISPC_MGR_FLD_CPR,
    213	DISPC_MGR_FLD_FIFOHANDCHECK,
    214	/* used to maintain a count of the above fields */
    215	DISPC_MGR_FLD_NUM,
    216};
    217
    218/* DISPC register field id */
    219enum dispc_feat_reg_field {
    220	FEAT_REG_FIRHINC,
    221	FEAT_REG_FIRVINC,
    222	FEAT_REG_FIFOHIGHTHRESHOLD,
    223	FEAT_REG_FIFOLOWTHRESHOLD,
    224	FEAT_REG_FIFOSIZE,
    225	FEAT_REG_HORIZONTALACCU,
    226	FEAT_REG_VERTICALACCU,
    227};
    228
    229struct dispc_reg_field {
    230	u16 reg;
    231	u8 high;
    232	u8 low;
    233};
    234
    235struct dispc_gamma_desc {
    236	u32 len;
    237	u32 bits;
    238	u16 reg;
    239	bool has_index;
    240};
    241
    242static const struct {
    243	const char *name;
    244	u32 vsync_irq;
    245	u32 framedone_irq;
    246	u32 sync_lost_irq;
    247	struct dispc_gamma_desc gamma;
    248	struct dispc_reg_field reg_desc[DISPC_MGR_FLD_NUM];
    249} mgr_desc[] = {
    250	[OMAP_DSS_CHANNEL_LCD] = {
    251		.name		= "LCD",
    252		.vsync_irq	= DISPC_IRQ_VSYNC,
    253		.framedone_irq	= DISPC_IRQ_FRAMEDONE,
    254		.sync_lost_irq	= DISPC_IRQ_SYNC_LOST,
    255		.gamma		= {
    256			.len	= 256,
    257			.bits	= 8,
    258			.reg	= DISPC_GAMMA_TABLE0,
    259			.has_index = true,
    260		},
    261		.reg_desc	= {
    262			[DISPC_MGR_FLD_ENABLE]		= { DISPC_CONTROL,  0,  0 },
    263			[DISPC_MGR_FLD_STNTFT]		= { DISPC_CONTROL,  3,  3 },
    264			[DISPC_MGR_FLD_GO]		= { DISPC_CONTROL,  5,  5 },
    265			[DISPC_MGR_FLD_TFTDATALINES]	= { DISPC_CONTROL,  9,  8 },
    266			[DISPC_MGR_FLD_STALLMODE]	= { DISPC_CONTROL, 11, 11 },
    267			[DISPC_MGR_FLD_TCKENABLE]	= { DISPC_CONFIG,  10, 10 },
    268			[DISPC_MGR_FLD_TCKSELECTION]	= { DISPC_CONFIG,  11, 11 },
    269			[DISPC_MGR_FLD_CPR]		= { DISPC_CONFIG,  15, 15 },
    270			[DISPC_MGR_FLD_FIFOHANDCHECK]	= { DISPC_CONFIG,  16, 16 },
    271		},
    272	},
    273	[OMAP_DSS_CHANNEL_DIGIT] = {
    274		.name		= "DIGIT",
    275		.vsync_irq	= DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN,
    276		.framedone_irq	= DISPC_IRQ_FRAMEDONETV,
    277		.sync_lost_irq	= DISPC_IRQ_SYNC_LOST_DIGIT,
    278		.gamma		= {
    279			.len	= 1024,
    280			.bits	= 10,
    281			.reg	= DISPC_GAMMA_TABLE2,
    282			.has_index = false,
    283		},
    284		.reg_desc	= {
    285			[DISPC_MGR_FLD_ENABLE]		= { DISPC_CONTROL,  1,  1 },
    286			[DISPC_MGR_FLD_STNTFT]		= { },
    287			[DISPC_MGR_FLD_GO]		= { DISPC_CONTROL,  6,  6 },
    288			[DISPC_MGR_FLD_TFTDATALINES]	= { },
    289			[DISPC_MGR_FLD_STALLMODE]	= { },
    290			[DISPC_MGR_FLD_TCKENABLE]	= { DISPC_CONFIG,  12, 12 },
    291			[DISPC_MGR_FLD_TCKSELECTION]	= { DISPC_CONFIG,  13, 13 },
    292			[DISPC_MGR_FLD_CPR]		= { },
    293			[DISPC_MGR_FLD_FIFOHANDCHECK]	= { DISPC_CONFIG,  16, 16 },
    294		},
    295	},
    296	[OMAP_DSS_CHANNEL_LCD2] = {
    297		.name		= "LCD2",
    298		.vsync_irq	= DISPC_IRQ_VSYNC2,
    299		.framedone_irq	= DISPC_IRQ_FRAMEDONE2,
    300		.sync_lost_irq	= DISPC_IRQ_SYNC_LOST2,
    301		.gamma		= {
    302			.len	= 256,
    303			.bits	= 8,
    304			.reg	= DISPC_GAMMA_TABLE1,
    305			.has_index = true,
    306		},
    307		.reg_desc	= {
    308			[DISPC_MGR_FLD_ENABLE]		= { DISPC_CONTROL2,  0,  0 },
    309			[DISPC_MGR_FLD_STNTFT]		= { DISPC_CONTROL2,  3,  3 },
    310			[DISPC_MGR_FLD_GO]		= { DISPC_CONTROL2,  5,  5 },
    311			[DISPC_MGR_FLD_TFTDATALINES]	= { DISPC_CONTROL2,  9,  8 },
    312			[DISPC_MGR_FLD_STALLMODE]	= { DISPC_CONTROL2, 11, 11 },
    313			[DISPC_MGR_FLD_TCKENABLE]	= { DISPC_CONFIG2,  10, 10 },
    314			[DISPC_MGR_FLD_TCKSELECTION]	= { DISPC_CONFIG2,  11, 11 },
    315			[DISPC_MGR_FLD_CPR]		= { DISPC_CONFIG2,  15, 15 },
    316			[DISPC_MGR_FLD_FIFOHANDCHECK]	= { DISPC_CONFIG2,  16, 16 },
    317		},
    318	},
    319	[OMAP_DSS_CHANNEL_LCD3] = {
    320		.name		= "LCD3",
    321		.vsync_irq	= DISPC_IRQ_VSYNC3,
    322		.framedone_irq	= DISPC_IRQ_FRAMEDONE3,
    323		.sync_lost_irq	= DISPC_IRQ_SYNC_LOST3,
    324		.gamma		= {
    325			.len	= 256,
    326			.bits	= 8,
    327			.reg	= DISPC_GAMMA_TABLE3,
    328			.has_index = true,
    329		},
    330		.reg_desc	= {
    331			[DISPC_MGR_FLD_ENABLE]		= { DISPC_CONTROL3,  0,  0 },
    332			[DISPC_MGR_FLD_STNTFT]		= { DISPC_CONTROL3,  3,  3 },
    333			[DISPC_MGR_FLD_GO]		= { DISPC_CONTROL3,  5,  5 },
    334			[DISPC_MGR_FLD_TFTDATALINES]	= { DISPC_CONTROL3,  9,  8 },
    335			[DISPC_MGR_FLD_STALLMODE]	= { DISPC_CONTROL3, 11, 11 },
    336			[DISPC_MGR_FLD_TCKENABLE]	= { DISPC_CONFIG3,  10, 10 },
    337			[DISPC_MGR_FLD_TCKSELECTION]	= { DISPC_CONFIG3,  11, 11 },
    338			[DISPC_MGR_FLD_CPR]		= { DISPC_CONFIG3,  15, 15 },
    339			[DISPC_MGR_FLD_FIFOHANDCHECK]	= { DISPC_CONFIG3,  16, 16 },
    340		},
    341	},
    342};
    343
    344static unsigned long dispc_fclk_rate(struct dispc_device *dispc);
    345static unsigned long dispc_core_clk_rate(struct dispc_device *dispc);
    346static unsigned long dispc_mgr_lclk_rate(struct dispc_device *dispc,
    347					 enum omap_channel channel);
    348static unsigned long dispc_mgr_pclk_rate(struct dispc_device *dispc,
    349					 enum omap_channel channel);
    350
    351static unsigned long dispc_plane_pclk_rate(struct dispc_device *dispc,
    352					   enum omap_plane_id plane);
    353static unsigned long dispc_plane_lclk_rate(struct dispc_device *dispc,
    354					   enum omap_plane_id plane);
    355
    356static inline void dispc_write_reg(struct dispc_device *dispc, u16 idx, u32 val)
    357{
    358	__raw_writel(val, dispc->base + idx);
    359}
    360
    361static inline u32 dispc_read_reg(struct dispc_device *dispc, u16 idx)
    362{
    363	return __raw_readl(dispc->base + idx);
    364}
    365
    366static u32 mgr_fld_read(struct dispc_device *dispc, enum omap_channel channel,
    367			enum mgr_reg_fields regfld)
    368{
    369	const struct dispc_reg_field *rfld = &mgr_desc[channel].reg_desc[regfld];
    370
    371	return REG_GET(dispc, rfld->reg, rfld->high, rfld->low);
    372}
    373
    374static void mgr_fld_write(struct dispc_device *dispc, enum omap_channel channel,
    375			  enum mgr_reg_fields regfld, int val)
    376{
    377	const struct dispc_reg_field *rfld = &mgr_desc[channel].reg_desc[regfld];
    378
    379	REG_FLD_MOD(dispc, rfld->reg, val, rfld->high, rfld->low);
    380}
    381
    382int dispc_get_num_ovls(struct dispc_device *dispc)
    383{
    384	return dispc->feat->num_ovls;
    385}
    386
    387int dispc_get_num_mgrs(struct dispc_device *dispc)
    388{
    389	return dispc->feat->num_mgrs;
    390}
    391
    392static void dispc_get_reg_field(struct dispc_device *dispc,
    393				enum dispc_feat_reg_field id,
    394				u8 *start, u8 *end)
    395{
    396	BUG_ON(id >= dispc->feat->num_reg_fields);
    397
    398	*start = dispc->feat->reg_fields[id].start;
    399	*end = dispc->feat->reg_fields[id].end;
    400}
    401
    402static bool dispc_has_feature(struct dispc_device *dispc,
    403			      enum dispc_feature_id id)
    404{
    405	unsigned int i;
    406
    407	for (i = 0; i < dispc->feat->num_features; i++) {
    408		if (dispc->feat->features[i] == id)
    409			return true;
    410	}
    411
    412	return false;
    413}
    414
    415#define SR(dispc, reg) \
    416	dispc->ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(dispc, DISPC_##reg)
    417#define RR(dispc, reg) \
    418	dispc_write_reg(dispc, DISPC_##reg, dispc->ctx[DISPC_##reg / sizeof(u32)])
    419
    420static void dispc_save_context(struct dispc_device *dispc)
    421{
    422	int i, j;
    423
    424	DSSDBG("dispc_save_context\n");
    425
    426	SR(dispc, IRQENABLE);
    427	SR(dispc, CONTROL);
    428	SR(dispc, CONFIG);
    429	SR(dispc, LINE_NUMBER);
    430	if (dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER) ||
    431			dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER))
    432		SR(dispc, GLOBAL_ALPHA);
    433	if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) {
    434		SR(dispc, CONTROL2);
    435		SR(dispc, CONFIG2);
    436	}
    437	if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) {
    438		SR(dispc, CONTROL3);
    439		SR(dispc, CONFIG3);
    440	}
    441
    442	for (i = 0; i < dispc_get_num_mgrs(dispc); i++) {
    443		SR(dispc, DEFAULT_COLOR(i));
    444		SR(dispc, TRANS_COLOR(i));
    445		SR(dispc, SIZE_MGR(i));
    446		if (i == OMAP_DSS_CHANNEL_DIGIT)
    447			continue;
    448		SR(dispc, TIMING_H(i));
    449		SR(dispc, TIMING_V(i));
    450		SR(dispc, POL_FREQ(i));
    451		SR(dispc, DIVISORo(i));
    452
    453		SR(dispc, DATA_CYCLE1(i));
    454		SR(dispc, DATA_CYCLE2(i));
    455		SR(dispc, DATA_CYCLE3(i));
    456
    457		if (dispc_has_feature(dispc, FEAT_CPR)) {
    458			SR(dispc, CPR_COEF_R(i));
    459			SR(dispc, CPR_COEF_G(i));
    460			SR(dispc, CPR_COEF_B(i));
    461		}
    462	}
    463
    464	for (i = 0; i < dispc_get_num_ovls(dispc); i++) {
    465		SR(dispc, OVL_BA0(i));
    466		SR(dispc, OVL_BA1(i));
    467		SR(dispc, OVL_POSITION(i));
    468		SR(dispc, OVL_SIZE(i));
    469		SR(dispc, OVL_ATTRIBUTES(i));
    470		SR(dispc, OVL_FIFO_THRESHOLD(i));
    471		SR(dispc, OVL_ROW_INC(i));
    472		SR(dispc, OVL_PIXEL_INC(i));
    473		if (dispc_has_feature(dispc, FEAT_PRELOAD))
    474			SR(dispc, OVL_PRELOAD(i));
    475		if (i == OMAP_DSS_GFX) {
    476			SR(dispc, OVL_WINDOW_SKIP(i));
    477			SR(dispc, OVL_TABLE_BA(i));
    478			continue;
    479		}
    480		SR(dispc, OVL_FIR(i));
    481		SR(dispc, OVL_PICTURE_SIZE(i));
    482		SR(dispc, OVL_ACCU0(i));
    483		SR(dispc, OVL_ACCU1(i));
    484
    485		for (j = 0; j < 8; j++)
    486			SR(dispc, OVL_FIR_COEF_H(i, j));
    487
    488		for (j = 0; j < 8; j++)
    489			SR(dispc, OVL_FIR_COEF_HV(i, j));
    490
    491		for (j = 0; j < 5; j++)
    492			SR(dispc, OVL_CONV_COEF(i, j));
    493
    494		if (dispc_has_feature(dispc, FEAT_FIR_COEF_V)) {
    495			for (j = 0; j < 8; j++)
    496				SR(dispc, OVL_FIR_COEF_V(i, j));
    497		}
    498
    499		if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) {
    500			SR(dispc, OVL_BA0_UV(i));
    501			SR(dispc, OVL_BA1_UV(i));
    502			SR(dispc, OVL_FIR2(i));
    503			SR(dispc, OVL_ACCU2_0(i));
    504			SR(dispc, OVL_ACCU2_1(i));
    505
    506			for (j = 0; j < 8; j++)
    507				SR(dispc, OVL_FIR_COEF_H2(i, j));
    508
    509			for (j = 0; j < 8; j++)
    510				SR(dispc, OVL_FIR_COEF_HV2(i, j));
    511
    512			for (j = 0; j < 8; j++)
    513				SR(dispc, OVL_FIR_COEF_V2(i, j));
    514		}
    515		if (dispc_has_feature(dispc, FEAT_ATTR2))
    516			SR(dispc, OVL_ATTRIBUTES2(i));
    517	}
    518
    519	if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV))
    520		SR(dispc, DIVISOR);
    521
    522	dispc->ctx_valid = true;
    523
    524	DSSDBG("context saved\n");
    525}
    526
    527static void dispc_restore_context(struct dispc_device *dispc)
    528{
    529	int i, j;
    530
    531	DSSDBG("dispc_restore_context\n");
    532
    533	if (!dispc->ctx_valid)
    534		return;
    535
    536	/*RR(dispc, IRQENABLE);*/
    537	/*RR(dispc, CONTROL);*/
    538	RR(dispc, CONFIG);
    539	RR(dispc, LINE_NUMBER);
    540	if (dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER) ||
    541			dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER))
    542		RR(dispc, GLOBAL_ALPHA);
    543	if (dispc_has_feature(dispc, FEAT_MGR_LCD2))
    544		RR(dispc, CONFIG2);
    545	if (dispc_has_feature(dispc, FEAT_MGR_LCD3))
    546		RR(dispc, CONFIG3);
    547
    548	for (i = 0; i < dispc_get_num_mgrs(dispc); i++) {
    549		RR(dispc, DEFAULT_COLOR(i));
    550		RR(dispc, TRANS_COLOR(i));
    551		RR(dispc, SIZE_MGR(i));
    552		if (i == OMAP_DSS_CHANNEL_DIGIT)
    553			continue;
    554		RR(dispc, TIMING_H(i));
    555		RR(dispc, TIMING_V(i));
    556		RR(dispc, POL_FREQ(i));
    557		RR(dispc, DIVISORo(i));
    558
    559		RR(dispc, DATA_CYCLE1(i));
    560		RR(dispc, DATA_CYCLE2(i));
    561		RR(dispc, DATA_CYCLE3(i));
    562
    563		if (dispc_has_feature(dispc, FEAT_CPR)) {
    564			RR(dispc, CPR_COEF_R(i));
    565			RR(dispc, CPR_COEF_G(i));
    566			RR(dispc, CPR_COEF_B(i));
    567		}
    568	}
    569
    570	for (i = 0; i < dispc_get_num_ovls(dispc); i++) {
    571		RR(dispc, OVL_BA0(i));
    572		RR(dispc, OVL_BA1(i));
    573		RR(dispc, OVL_POSITION(i));
    574		RR(dispc, OVL_SIZE(i));
    575		RR(dispc, OVL_ATTRIBUTES(i));
    576		RR(dispc, OVL_FIFO_THRESHOLD(i));
    577		RR(dispc, OVL_ROW_INC(i));
    578		RR(dispc, OVL_PIXEL_INC(i));
    579		if (dispc_has_feature(dispc, FEAT_PRELOAD))
    580			RR(dispc, OVL_PRELOAD(i));
    581		if (i == OMAP_DSS_GFX) {
    582			RR(dispc, OVL_WINDOW_SKIP(i));
    583			RR(dispc, OVL_TABLE_BA(i));
    584			continue;
    585		}
    586		RR(dispc, OVL_FIR(i));
    587		RR(dispc, OVL_PICTURE_SIZE(i));
    588		RR(dispc, OVL_ACCU0(i));
    589		RR(dispc, OVL_ACCU1(i));
    590
    591		for (j = 0; j < 8; j++)
    592			RR(dispc, OVL_FIR_COEF_H(i, j));
    593
    594		for (j = 0; j < 8; j++)
    595			RR(dispc, OVL_FIR_COEF_HV(i, j));
    596
    597		for (j = 0; j < 5; j++)
    598			RR(dispc, OVL_CONV_COEF(i, j));
    599
    600		if (dispc_has_feature(dispc, FEAT_FIR_COEF_V)) {
    601			for (j = 0; j < 8; j++)
    602				RR(dispc, OVL_FIR_COEF_V(i, j));
    603		}
    604
    605		if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) {
    606			RR(dispc, OVL_BA0_UV(i));
    607			RR(dispc, OVL_BA1_UV(i));
    608			RR(dispc, OVL_FIR2(i));
    609			RR(dispc, OVL_ACCU2_0(i));
    610			RR(dispc, OVL_ACCU2_1(i));
    611
    612			for (j = 0; j < 8; j++)
    613				RR(dispc, OVL_FIR_COEF_H2(i, j));
    614
    615			for (j = 0; j < 8; j++)
    616				RR(dispc, OVL_FIR_COEF_HV2(i, j));
    617
    618			for (j = 0; j < 8; j++)
    619				RR(dispc, OVL_FIR_COEF_V2(i, j));
    620		}
    621		if (dispc_has_feature(dispc, FEAT_ATTR2))
    622			RR(dispc, OVL_ATTRIBUTES2(i));
    623	}
    624
    625	if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV))
    626		RR(dispc, DIVISOR);
    627
    628	/* enable last, because LCD & DIGIT enable are here */
    629	RR(dispc, CONTROL);
    630	if (dispc_has_feature(dispc, FEAT_MGR_LCD2))
    631		RR(dispc, CONTROL2);
    632	if (dispc_has_feature(dispc, FEAT_MGR_LCD3))
    633		RR(dispc, CONTROL3);
    634	/* clear spurious SYNC_LOST_DIGIT interrupts */
    635	dispc_clear_irqstatus(dispc, DISPC_IRQ_SYNC_LOST_DIGIT);
    636
    637	/*
    638	 * enable last so IRQs won't trigger before
    639	 * the context is fully restored
    640	 */
    641	RR(dispc, IRQENABLE);
    642
    643	DSSDBG("context restored\n");
    644}
    645
    646#undef SR
    647#undef RR
    648
    649int dispc_runtime_get(struct dispc_device *dispc)
    650{
    651	int r;
    652
    653	DSSDBG("dispc_runtime_get\n");
    654
    655	r = pm_runtime_get_sync(&dispc->pdev->dev);
    656	if (WARN_ON(r < 0)) {
    657		pm_runtime_put_noidle(&dispc->pdev->dev);
    658		return r;
    659	}
    660	return 0;
    661}
    662
    663void dispc_runtime_put(struct dispc_device *dispc)
    664{
    665	int r;
    666
    667	DSSDBG("dispc_runtime_put\n");
    668
    669	r = pm_runtime_put_sync(&dispc->pdev->dev);
    670	WARN_ON(r < 0 && r != -ENOSYS);
    671}
    672
    673u32 dispc_mgr_get_vsync_irq(struct dispc_device *dispc,
    674				   enum omap_channel channel)
    675{
    676	return mgr_desc[channel].vsync_irq;
    677}
    678
    679u32 dispc_mgr_get_framedone_irq(struct dispc_device *dispc,
    680				       enum omap_channel channel)
    681{
    682	if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc->feat->no_framedone_tv)
    683		return 0;
    684
    685	return mgr_desc[channel].framedone_irq;
    686}
    687
    688u32 dispc_mgr_get_sync_lost_irq(struct dispc_device *dispc,
    689				       enum omap_channel channel)
    690{
    691	return mgr_desc[channel].sync_lost_irq;
    692}
    693
    694u32 dispc_wb_get_framedone_irq(struct dispc_device *dispc)
    695{
    696	return DISPC_IRQ_FRAMEDONEWB;
    697}
    698
    699void dispc_mgr_enable(struct dispc_device *dispc,
    700			     enum omap_channel channel, bool enable)
    701{
    702	mgr_fld_write(dispc, channel, DISPC_MGR_FLD_ENABLE, enable);
    703	/* flush posted write */
    704	mgr_fld_read(dispc, channel, DISPC_MGR_FLD_ENABLE);
    705}
    706
    707static bool dispc_mgr_is_enabled(struct dispc_device *dispc,
    708				 enum omap_channel channel)
    709{
    710	return !!mgr_fld_read(dispc, channel, DISPC_MGR_FLD_ENABLE);
    711}
    712
    713bool dispc_mgr_go_busy(struct dispc_device *dispc,
    714			      enum omap_channel channel)
    715{
    716	return mgr_fld_read(dispc, channel, DISPC_MGR_FLD_GO) == 1;
    717}
    718
    719void dispc_mgr_go(struct dispc_device *dispc, enum omap_channel channel)
    720{
    721	WARN_ON(!dispc_mgr_is_enabled(dispc, channel));
    722	WARN_ON(dispc_mgr_go_busy(dispc, channel));
    723
    724	DSSDBG("GO %s\n", mgr_desc[channel].name);
    725
    726	mgr_fld_write(dispc, channel, DISPC_MGR_FLD_GO, 1);
    727}
    728
    729bool dispc_wb_go_busy(struct dispc_device *dispc)
    730{
    731	return REG_GET(dispc, DISPC_CONTROL2, 6, 6) == 1;
    732}
    733
    734void dispc_wb_go(struct dispc_device *dispc)
    735{
    736	enum omap_plane_id plane = OMAP_DSS_WB;
    737	bool enable, go;
    738
    739	enable = REG_GET(dispc, DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1;
    740
    741	if (!enable)
    742		return;
    743
    744	go = REG_GET(dispc, DISPC_CONTROL2, 6, 6) == 1;
    745	if (go) {
    746		DSSERR("GO bit not down for WB\n");
    747		return;
    748	}
    749
    750	REG_FLD_MOD(dispc, DISPC_CONTROL2, 1, 6, 6);
    751}
    752
    753static void dispc_ovl_write_firh_reg(struct dispc_device *dispc,
    754				     enum omap_plane_id plane, int reg,
    755				     u32 value)
    756{
    757	dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_H(plane, reg), value);
    758}
    759
    760static void dispc_ovl_write_firhv_reg(struct dispc_device *dispc,
    761				      enum omap_plane_id plane, int reg,
    762				      u32 value)
    763{
    764	dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_HV(plane, reg), value);
    765}
    766
    767static void dispc_ovl_write_firv_reg(struct dispc_device *dispc,
    768				     enum omap_plane_id plane, int reg,
    769				     u32 value)
    770{
    771	dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_V(plane, reg), value);
    772}
    773
    774static void dispc_ovl_write_firh2_reg(struct dispc_device *dispc,
    775				      enum omap_plane_id plane, int reg,
    776				      u32 value)
    777{
    778	BUG_ON(plane == OMAP_DSS_GFX);
    779
    780	dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_H2(plane, reg), value);
    781}
    782
    783static void dispc_ovl_write_firhv2_reg(struct dispc_device *dispc,
    784				       enum omap_plane_id plane, int reg,
    785				       u32 value)
    786{
    787	BUG_ON(plane == OMAP_DSS_GFX);
    788
    789	dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_HV2(plane, reg), value);
    790}
    791
    792static void dispc_ovl_write_firv2_reg(struct dispc_device *dispc,
    793				      enum omap_plane_id plane, int reg,
    794				      u32 value)
    795{
    796	BUG_ON(plane == OMAP_DSS_GFX);
    797
    798	dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_V2(plane, reg), value);
    799}
    800
    801static void dispc_ovl_set_scale_coef(struct dispc_device *dispc,
    802				     enum omap_plane_id plane, int fir_hinc,
    803				     int fir_vinc, int five_taps,
    804				     enum omap_color_component color_comp)
    805{
    806	const struct dispc_coef *h_coef, *v_coef;
    807	int i;
    808
    809	h_coef = dispc_ovl_get_scale_coef(fir_hinc, true);
    810	v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps);
    811
    812	if (!h_coef || !v_coef) {
    813		dev_err(&dispc->pdev->dev, "%s: failed to find scale coefs\n",
    814			__func__);
    815		return;
    816	}
    817
    818	for (i = 0; i < 8; i++) {
    819		u32 h, hv;
    820
    821		h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0)
    822			| FLD_VAL(h_coef[i].hc1_vc0, 15, 8)
    823			| FLD_VAL(h_coef[i].hc2_vc1, 23, 16)
    824			| FLD_VAL(h_coef[i].hc3_vc2, 31, 24);
    825		hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0)
    826			| FLD_VAL(v_coef[i].hc1_vc0, 15, 8)
    827			| FLD_VAL(v_coef[i].hc2_vc1, 23, 16)
    828			| FLD_VAL(v_coef[i].hc3_vc2, 31, 24);
    829
    830		if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
    831			dispc_ovl_write_firh_reg(dispc, plane, i, h);
    832			dispc_ovl_write_firhv_reg(dispc, plane, i, hv);
    833		} else {
    834			dispc_ovl_write_firh2_reg(dispc, plane, i, h);
    835			dispc_ovl_write_firhv2_reg(dispc, plane, i, hv);
    836		}
    837
    838	}
    839
    840	if (five_taps) {
    841		for (i = 0; i < 8; i++) {
    842			u32 v;
    843			v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0)
    844				| FLD_VAL(v_coef[i].hc4_vc22, 15, 8);
    845			if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y)
    846				dispc_ovl_write_firv_reg(dispc, plane, i, v);
    847			else
    848				dispc_ovl_write_firv2_reg(dispc, plane, i, v);
    849		}
    850	}
    851}
    852
    853struct csc_coef_yuv2rgb {
    854	int ry, rcb, rcr, gy, gcb, gcr, by, bcb, bcr;
    855	bool full_range;
    856};
    857
    858struct csc_coef_rgb2yuv {
    859	int yr, yg, yb, cbr, cbg, cbb, crr, crg, crb;
    860	bool full_range;
    861};
    862
    863static void dispc_ovl_write_color_conv_coef(struct dispc_device *dispc,
    864					    enum omap_plane_id plane,
    865					    const struct csc_coef_yuv2rgb *ct)
    866{
    867#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
    868
    869	dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry));
    870	dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy,  ct->rcb));
    871	dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr));
    872	dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by));
    873	dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb));
    874
    875	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11);
    876
    877#undef CVAL
    878}
    879
    880/* YUV -> RGB, ITU-R BT.601, full range */
    881static const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt601_full = {
    882	256,   0,  358,		/* ry, rcb, rcr |1.000  0.000  1.402|*/
    883	256, -88, -182,		/* gy, gcb, gcr |1.000 -0.344 -0.714|*/
    884	256, 452,    0,		/* by, bcb, bcr |1.000  1.772  0.000|*/
    885	true,			/* full range */
    886};
    887
    888/* YUV -> RGB, ITU-R BT.601, limited range */
    889static const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt601_lim = {
    890	298,    0,  409,	/* ry, rcb, rcr |1.164  0.000  1.596|*/
    891	298, -100, -208,	/* gy, gcb, gcr |1.164 -0.392 -0.813|*/
    892	298,  516,    0,	/* by, bcb, bcr |1.164  2.017  0.000|*/
    893	false,			/* limited range */
    894};
    895
    896/* YUV -> RGB, ITU-R BT.709, full range */
    897static const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt709_full = {
    898	256,    0,  402,        /* ry, rcb, rcr |1.000  0.000  1.570|*/
    899	256,  -48, -120,        /* gy, gcb, gcr |1.000 -0.187 -0.467|*/
    900	256,  475,    0,        /* by, bcb, bcr |1.000  1.856  0.000|*/
    901	true,                   /* full range */
    902};
    903
    904/* YUV -> RGB, ITU-R BT.709, limited range */
    905static const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt709_lim = {
    906	298,    0,  459,	/* ry, rcb, rcr |1.164  0.000  1.793|*/
    907	298,  -55, -136,	/* gy, gcb, gcr |1.164 -0.213 -0.533|*/
    908	298,  541,    0,	/* by, bcb, bcr |1.164  2.112  0.000|*/
    909	false,			/* limited range */
    910};
    911
    912static void dispc_ovl_set_csc(struct dispc_device *dispc,
    913			      enum omap_plane_id plane,
    914			      enum drm_color_encoding color_encoding,
    915			      enum drm_color_range color_range)
    916{
    917	const struct csc_coef_yuv2rgb *csc;
    918
    919	switch (color_encoding) {
    920	default:
    921	case DRM_COLOR_YCBCR_BT601:
    922		if (color_range == DRM_COLOR_YCBCR_FULL_RANGE)
    923			csc = &coefs_yuv2rgb_bt601_full;
    924		else
    925			csc = &coefs_yuv2rgb_bt601_lim;
    926		break;
    927	case DRM_COLOR_YCBCR_BT709:
    928		if (color_range == DRM_COLOR_YCBCR_FULL_RANGE)
    929			csc = &coefs_yuv2rgb_bt709_full;
    930		else
    931			csc = &coefs_yuv2rgb_bt709_lim;
    932		break;
    933	}
    934
    935	dispc_ovl_write_color_conv_coef(dispc, plane, csc);
    936}
    937
    938static void dispc_ovl_set_ba0(struct dispc_device *dispc,
    939			      enum omap_plane_id plane, u32 paddr)
    940{
    941	dispc_write_reg(dispc, DISPC_OVL_BA0(plane), paddr);
    942}
    943
    944static void dispc_ovl_set_ba1(struct dispc_device *dispc,
    945			      enum omap_plane_id plane, u32 paddr)
    946{
    947	dispc_write_reg(dispc, DISPC_OVL_BA1(plane), paddr);
    948}
    949
    950static void dispc_ovl_set_ba0_uv(struct dispc_device *dispc,
    951				 enum omap_plane_id plane, u32 paddr)
    952{
    953	dispc_write_reg(dispc, DISPC_OVL_BA0_UV(plane), paddr);
    954}
    955
    956static void dispc_ovl_set_ba1_uv(struct dispc_device *dispc,
    957				 enum omap_plane_id plane, u32 paddr)
    958{
    959	dispc_write_reg(dispc, DISPC_OVL_BA1_UV(plane), paddr);
    960}
    961
    962static void dispc_ovl_set_pos(struct dispc_device *dispc,
    963			      enum omap_plane_id plane,
    964			      enum omap_overlay_caps caps, int x, int y)
    965{
    966	u32 val;
    967
    968	if ((caps & OMAP_DSS_OVL_CAP_POS) == 0)
    969		return;
    970
    971	val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
    972
    973	dispc_write_reg(dispc, DISPC_OVL_POSITION(plane), val);
    974}
    975
    976static void dispc_ovl_set_input_size(struct dispc_device *dispc,
    977				     enum omap_plane_id plane, int width,
    978				     int height)
    979{
    980	u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
    981
    982	if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB)
    983		dispc_write_reg(dispc, DISPC_OVL_SIZE(plane), val);
    984	else
    985		dispc_write_reg(dispc, DISPC_OVL_PICTURE_SIZE(plane), val);
    986}
    987
    988static void dispc_ovl_set_output_size(struct dispc_device *dispc,
    989				      enum omap_plane_id plane, int width,
    990				      int height)
    991{
    992	u32 val;
    993
    994	BUG_ON(plane == OMAP_DSS_GFX);
    995
    996	val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
    997
    998	if (plane == OMAP_DSS_WB)
    999		dispc_write_reg(dispc, DISPC_OVL_PICTURE_SIZE(plane), val);
   1000	else
   1001		dispc_write_reg(dispc, DISPC_OVL_SIZE(plane), val);
   1002}
   1003
   1004static void dispc_ovl_set_zorder(struct dispc_device *dispc,
   1005				 enum omap_plane_id plane,
   1006				 enum omap_overlay_caps caps, u8 zorder)
   1007{
   1008	if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
   1009		return;
   1010
   1011	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26);
   1012}
   1013
   1014static void dispc_ovl_enable_zorder_planes(struct dispc_device *dispc)
   1015{
   1016	int i;
   1017
   1018	if (!dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER))
   1019		return;
   1020
   1021	for (i = 0; i < dispc_get_num_ovls(dispc); i++)
   1022		REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(i), 1, 25, 25);
   1023}
   1024
   1025static void dispc_ovl_set_pre_mult_alpha(struct dispc_device *dispc,
   1026					 enum omap_plane_id plane,
   1027					 enum omap_overlay_caps caps,
   1028					 bool enable)
   1029{
   1030	if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
   1031		return;
   1032
   1033	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
   1034}
   1035
   1036static void dispc_ovl_setup_global_alpha(struct dispc_device *dispc,
   1037					 enum omap_plane_id plane,
   1038					 enum omap_overlay_caps caps,
   1039					 u8 global_alpha)
   1040{
   1041	static const unsigned int shifts[] = { 0, 8, 16, 24, };
   1042	int shift;
   1043
   1044	if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
   1045		return;
   1046
   1047	shift = shifts[plane];
   1048	REG_FLD_MOD(dispc, DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift);
   1049}
   1050
   1051static void dispc_ovl_set_pix_inc(struct dispc_device *dispc,
   1052				  enum omap_plane_id plane, s32 inc)
   1053{
   1054	dispc_write_reg(dispc, DISPC_OVL_PIXEL_INC(plane), inc);
   1055}
   1056
   1057static void dispc_ovl_set_row_inc(struct dispc_device *dispc,
   1058				  enum omap_plane_id plane, s32 inc)
   1059{
   1060	dispc_write_reg(dispc, DISPC_OVL_ROW_INC(plane), inc);
   1061}
   1062
   1063static void dispc_ovl_set_color_mode(struct dispc_device *dispc,
   1064				     enum omap_plane_id plane, u32 fourcc)
   1065{
   1066	u32 m = 0;
   1067	if (plane != OMAP_DSS_GFX) {
   1068		switch (fourcc) {
   1069		case DRM_FORMAT_NV12:
   1070			m = 0x0; break;
   1071		case DRM_FORMAT_XRGB4444:
   1072			m = 0x1; break;
   1073		case DRM_FORMAT_RGBA4444:
   1074			m = 0x2; break;
   1075		case DRM_FORMAT_RGBX4444:
   1076			m = 0x4; break;
   1077		case DRM_FORMAT_ARGB4444:
   1078			m = 0x5; break;
   1079		case DRM_FORMAT_RGB565:
   1080			m = 0x6; break;
   1081		case DRM_FORMAT_ARGB1555:
   1082			m = 0x7; break;
   1083		case DRM_FORMAT_XRGB8888:
   1084			m = 0x8; break;
   1085		case DRM_FORMAT_RGB888:
   1086			m = 0x9; break;
   1087		case DRM_FORMAT_YUYV:
   1088			m = 0xa; break;
   1089		case DRM_FORMAT_UYVY:
   1090			m = 0xb; break;
   1091		case DRM_FORMAT_ARGB8888:
   1092			m = 0xc; break;
   1093		case DRM_FORMAT_RGBA8888:
   1094			m = 0xd; break;
   1095		case DRM_FORMAT_RGBX8888:
   1096			m = 0xe; break;
   1097		case DRM_FORMAT_XRGB1555:
   1098			m = 0xf; break;
   1099		default:
   1100			BUG(); return;
   1101		}
   1102	} else {
   1103		switch (fourcc) {
   1104		case DRM_FORMAT_RGBX4444:
   1105			m = 0x4; break;
   1106		case DRM_FORMAT_ARGB4444:
   1107			m = 0x5; break;
   1108		case DRM_FORMAT_RGB565:
   1109			m = 0x6; break;
   1110		case DRM_FORMAT_ARGB1555:
   1111			m = 0x7; break;
   1112		case DRM_FORMAT_XRGB8888:
   1113			m = 0x8; break;
   1114		case DRM_FORMAT_RGB888:
   1115			m = 0x9; break;
   1116		case DRM_FORMAT_XRGB4444:
   1117			m = 0xa; break;
   1118		case DRM_FORMAT_RGBA4444:
   1119			m = 0xb; break;
   1120		case DRM_FORMAT_ARGB8888:
   1121			m = 0xc; break;
   1122		case DRM_FORMAT_RGBA8888:
   1123			m = 0xd; break;
   1124		case DRM_FORMAT_RGBX8888:
   1125			m = 0xe; break;
   1126		case DRM_FORMAT_XRGB1555:
   1127			m = 0xf; break;
   1128		default:
   1129			BUG(); return;
   1130		}
   1131	}
   1132
   1133	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
   1134}
   1135
   1136static void dispc_ovl_configure_burst_type(struct dispc_device *dispc,
   1137					   enum omap_plane_id plane,
   1138					   enum omap_dss_rotation_type rotation)
   1139{
   1140	if (dispc_has_feature(dispc, FEAT_BURST_2D) == 0)
   1141		return;
   1142
   1143	if (rotation == OMAP_DSS_ROT_TILER)
   1144		REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29);
   1145	else
   1146		REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29);
   1147}
   1148
   1149static void dispc_ovl_set_channel_out(struct dispc_device *dispc,
   1150				      enum omap_plane_id plane,
   1151				      enum omap_channel channel)
   1152{
   1153	int shift;
   1154	u32 val;
   1155	int chan = 0, chan2 = 0;
   1156
   1157	switch (plane) {
   1158	case OMAP_DSS_GFX:
   1159		shift = 8;
   1160		break;
   1161	case OMAP_DSS_VIDEO1:
   1162	case OMAP_DSS_VIDEO2:
   1163	case OMAP_DSS_VIDEO3:
   1164		shift = 16;
   1165		break;
   1166	default:
   1167		BUG();
   1168		return;
   1169	}
   1170
   1171	val = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane));
   1172	if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) {
   1173		switch (channel) {
   1174		case OMAP_DSS_CHANNEL_LCD:
   1175			chan = 0;
   1176			chan2 = 0;
   1177			break;
   1178		case OMAP_DSS_CHANNEL_DIGIT:
   1179			chan = 1;
   1180			chan2 = 0;
   1181			break;
   1182		case OMAP_DSS_CHANNEL_LCD2:
   1183			chan = 0;
   1184			chan2 = 1;
   1185			break;
   1186		case OMAP_DSS_CHANNEL_LCD3:
   1187			if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) {
   1188				chan = 0;
   1189				chan2 = 2;
   1190			} else {
   1191				BUG();
   1192				return;
   1193			}
   1194			break;
   1195		case OMAP_DSS_CHANNEL_WB:
   1196			chan = 0;
   1197			chan2 = 3;
   1198			break;
   1199		default:
   1200			BUG();
   1201			return;
   1202		}
   1203
   1204		val = FLD_MOD(val, chan, shift, shift);
   1205		val = FLD_MOD(val, chan2, 31, 30);
   1206	} else {
   1207		val = FLD_MOD(val, channel, shift, shift);
   1208	}
   1209	dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), val);
   1210}
   1211
   1212static enum omap_channel dispc_ovl_get_channel_out(struct dispc_device *dispc,
   1213						   enum omap_plane_id plane)
   1214{
   1215	int shift;
   1216	u32 val;
   1217
   1218	switch (plane) {
   1219	case OMAP_DSS_GFX:
   1220		shift = 8;
   1221		break;
   1222	case OMAP_DSS_VIDEO1:
   1223	case OMAP_DSS_VIDEO2:
   1224	case OMAP_DSS_VIDEO3:
   1225		shift = 16;
   1226		break;
   1227	default:
   1228		BUG();
   1229		return 0;
   1230	}
   1231
   1232	val = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane));
   1233
   1234	if (FLD_GET(val, shift, shift) == 1)
   1235		return OMAP_DSS_CHANNEL_DIGIT;
   1236
   1237	if (!dispc_has_feature(dispc, FEAT_MGR_LCD2))
   1238		return OMAP_DSS_CHANNEL_LCD;
   1239
   1240	switch (FLD_GET(val, 31, 30)) {
   1241	case 0:
   1242	default:
   1243		return OMAP_DSS_CHANNEL_LCD;
   1244	case 1:
   1245		return OMAP_DSS_CHANNEL_LCD2;
   1246	case 2:
   1247		return OMAP_DSS_CHANNEL_LCD3;
   1248	case 3:
   1249		return OMAP_DSS_CHANNEL_WB;
   1250	}
   1251}
   1252
   1253static void dispc_ovl_set_burst_size(struct dispc_device *dispc,
   1254				     enum omap_plane_id plane,
   1255				     enum omap_burst_size burst_size)
   1256{
   1257	static const unsigned int shifts[] = { 6, 14, 14, 14, 14, };
   1258	int shift;
   1259
   1260	shift = shifts[plane];
   1261	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), burst_size,
   1262		    shift + 1, shift);
   1263}
   1264
   1265static void dispc_configure_burst_sizes(struct dispc_device *dispc)
   1266{
   1267	int i;
   1268	const int burst_size = BURST_SIZE_X8;
   1269
   1270	/* Configure burst size always to maximum size */
   1271	for (i = 0; i < dispc_get_num_ovls(dispc); ++i)
   1272		dispc_ovl_set_burst_size(dispc, i, burst_size);
   1273	if (dispc->feat->has_writeback)
   1274		dispc_ovl_set_burst_size(dispc, OMAP_DSS_WB, burst_size);
   1275}
   1276
   1277static u32 dispc_ovl_get_burst_size(struct dispc_device *dispc,
   1278				    enum omap_plane_id plane)
   1279{
   1280	/* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
   1281	return dispc->feat->burst_size_unit * 8;
   1282}
   1283
   1284bool dispc_ovl_color_mode_supported(struct dispc_device *dispc,
   1285				    enum omap_plane_id plane, u32 fourcc)
   1286{
   1287	const u32 *modes;
   1288	unsigned int i;
   1289
   1290	modes = dispc->feat->supported_color_modes[plane];
   1291
   1292	for (i = 0; modes[i]; ++i) {
   1293		if (modes[i] == fourcc)
   1294			return true;
   1295	}
   1296
   1297	return false;
   1298}
   1299
   1300const u32 *dispc_ovl_get_color_modes(struct dispc_device *dispc,
   1301					    enum omap_plane_id plane)
   1302{
   1303	return dispc->feat->supported_color_modes[plane];
   1304}
   1305
   1306static void dispc_mgr_enable_cpr(struct dispc_device *dispc,
   1307				 enum omap_channel channel, bool enable)
   1308{
   1309	if (channel == OMAP_DSS_CHANNEL_DIGIT)
   1310		return;
   1311
   1312	mgr_fld_write(dispc, channel, DISPC_MGR_FLD_CPR, enable);
   1313}
   1314
   1315static void dispc_mgr_set_cpr_coef(struct dispc_device *dispc,
   1316				   enum omap_channel channel,
   1317				   const struct omap_dss_cpr_coefs *coefs)
   1318{
   1319	u32 coef_r, coef_g, coef_b;
   1320
   1321	if (!dss_mgr_is_lcd(channel))
   1322		return;
   1323
   1324	coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) |
   1325		FLD_VAL(coefs->rb, 9, 0);
   1326	coef_g = FLD_VAL(coefs->gr, 31, 22) | FLD_VAL(coefs->gg, 20, 11) |
   1327		FLD_VAL(coefs->gb, 9, 0);
   1328	coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) |
   1329		FLD_VAL(coefs->bb, 9, 0);
   1330
   1331	dispc_write_reg(dispc, DISPC_CPR_COEF_R(channel), coef_r);
   1332	dispc_write_reg(dispc, DISPC_CPR_COEF_G(channel), coef_g);
   1333	dispc_write_reg(dispc, DISPC_CPR_COEF_B(channel), coef_b);
   1334}
   1335
   1336static void dispc_ovl_set_vid_color_conv(struct dispc_device *dispc,
   1337					 enum omap_plane_id plane, bool enable)
   1338{
   1339	u32 val;
   1340
   1341	BUG_ON(plane == OMAP_DSS_GFX);
   1342
   1343	val = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane));
   1344	val = FLD_MOD(val, enable, 9, 9);
   1345	dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), val);
   1346}
   1347
   1348static void dispc_ovl_enable_replication(struct dispc_device *dispc,
   1349					 enum omap_plane_id plane,
   1350					 enum omap_overlay_caps caps,
   1351					 bool enable)
   1352{
   1353	static const unsigned int shifts[] = { 5, 10, 10, 10 };
   1354	int shift;
   1355
   1356	if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0)
   1357		return;
   1358
   1359	shift = shifts[plane];
   1360	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift);
   1361}
   1362
   1363static void dispc_mgr_set_size(struct dispc_device *dispc,
   1364			       enum omap_channel channel, u16 width, u16 height)
   1365{
   1366	u32 val;
   1367
   1368	val = FLD_VAL(height - 1, dispc->feat->mgr_height_start, 16) |
   1369		FLD_VAL(width - 1, dispc->feat->mgr_width_start, 0);
   1370
   1371	dispc_write_reg(dispc, DISPC_SIZE_MGR(channel), val);
   1372}
   1373
   1374static void dispc_init_fifos(struct dispc_device *dispc)
   1375{
   1376	u32 size;
   1377	int fifo;
   1378	u8 start, end;
   1379	u32 unit;
   1380	int i;
   1381
   1382	unit = dispc->feat->buffer_size_unit;
   1383
   1384	dispc_get_reg_field(dispc, FEAT_REG_FIFOSIZE, &start, &end);
   1385
   1386	for (fifo = 0; fifo < dispc->feat->num_fifos; ++fifo) {
   1387		size = REG_GET(dispc, DISPC_OVL_FIFO_SIZE_STATUS(fifo),
   1388			       start, end);
   1389		size *= unit;
   1390		dispc->fifo_size[fifo] = size;
   1391
   1392		/*
   1393		 * By default fifos are mapped directly to overlays, fifo 0 to
   1394		 * ovl 0, fifo 1 to ovl 1, etc.
   1395		 */
   1396		dispc->fifo_assignment[fifo] = fifo;
   1397	}
   1398
   1399	/*
   1400	 * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo
   1401	 * causes problems with certain use cases, like using the tiler in 2D
   1402	 * mode. The below hack swaps the fifos of GFX and WB planes, thus
   1403	 * giving GFX plane a larger fifo. WB but should work fine with a
   1404	 * smaller fifo.
   1405	 */
   1406	if (dispc->feat->gfx_fifo_workaround) {
   1407		u32 v;
   1408
   1409		v = dispc_read_reg(dispc, DISPC_GLOBAL_BUFFER);
   1410
   1411		v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */
   1412		v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */
   1413		v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */
   1414		v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */
   1415
   1416		dispc_write_reg(dispc, DISPC_GLOBAL_BUFFER, v);
   1417
   1418		dispc->fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB;
   1419		dispc->fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX;
   1420	}
   1421
   1422	/*
   1423	 * Setup default fifo thresholds.
   1424	 */
   1425	for (i = 0; i < dispc_get_num_ovls(dispc); ++i) {
   1426		u32 low, high;
   1427		const bool use_fifomerge = false;
   1428		const bool manual_update = false;
   1429
   1430		dispc_ovl_compute_fifo_thresholds(dispc, i, &low, &high,
   1431						  use_fifomerge, manual_update);
   1432
   1433		dispc_ovl_set_fifo_threshold(dispc, i, low, high);
   1434	}
   1435
   1436	if (dispc->feat->has_writeback) {
   1437		u32 low, high;
   1438		const bool use_fifomerge = false;
   1439		const bool manual_update = false;
   1440
   1441		dispc_ovl_compute_fifo_thresholds(dispc, OMAP_DSS_WB,
   1442						  &low, &high, use_fifomerge,
   1443						  manual_update);
   1444
   1445		dispc_ovl_set_fifo_threshold(dispc, OMAP_DSS_WB, low, high);
   1446	}
   1447}
   1448
   1449static u32 dispc_ovl_get_fifo_size(struct dispc_device *dispc,
   1450				   enum omap_plane_id plane)
   1451{
   1452	int fifo;
   1453	u32 size = 0;
   1454
   1455	for (fifo = 0; fifo < dispc->feat->num_fifos; ++fifo) {
   1456		if (dispc->fifo_assignment[fifo] == plane)
   1457			size += dispc->fifo_size[fifo];
   1458	}
   1459
   1460	return size;
   1461}
   1462
   1463void dispc_ovl_set_fifo_threshold(struct dispc_device *dispc,
   1464				  enum omap_plane_id plane,
   1465				  u32 low, u32 high)
   1466{
   1467	u8 hi_start, hi_end, lo_start, lo_end;
   1468	u32 unit;
   1469
   1470	unit = dispc->feat->buffer_size_unit;
   1471
   1472	WARN_ON(low % unit != 0);
   1473	WARN_ON(high % unit != 0);
   1474
   1475	low /= unit;
   1476	high /= unit;
   1477
   1478	dispc_get_reg_field(dispc, FEAT_REG_FIFOHIGHTHRESHOLD,
   1479			    &hi_start, &hi_end);
   1480	dispc_get_reg_field(dispc, FEAT_REG_FIFOLOWTHRESHOLD,
   1481			    &lo_start, &lo_end);
   1482
   1483	DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n",
   1484			plane,
   1485			REG_GET(dispc, DISPC_OVL_FIFO_THRESHOLD(plane),
   1486				lo_start, lo_end) * unit,
   1487			REG_GET(dispc, DISPC_OVL_FIFO_THRESHOLD(plane),
   1488				hi_start, hi_end) * unit,
   1489			low * unit, high * unit);
   1490
   1491	dispc_write_reg(dispc, DISPC_OVL_FIFO_THRESHOLD(plane),
   1492			FLD_VAL(high, hi_start, hi_end) |
   1493			FLD_VAL(low, lo_start, lo_end));
   1494
   1495	/*
   1496	 * configure the preload to the pipeline's high threhold, if HT it's too
   1497	 * large for the preload field, set the threshold to the maximum value
   1498	 * that can be held by the preload register
   1499	 */
   1500	if (dispc_has_feature(dispc, FEAT_PRELOAD) &&
   1501	    dispc->feat->set_max_preload && plane != OMAP_DSS_WB)
   1502		dispc_write_reg(dispc, DISPC_OVL_PRELOAD(plane),
   1503				min(high, 0xfffu));
   1504}
   1505
   1506void dispc_enable_fifomerge(struct dispc_device *dispc, bool enable)
   1507{
   1508	if (!dispc_has_feature(dispc, FEAT_FIFO_MERGE)) {
   1509		WARN_ON(enable);
   1510		return;
   1511	}
   1512
   1513	DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
   1514	REG_FLD_MOD(dispc, DISPC_CONFIG, enable ? 1 : 0, 14, 14);
   1515}
   1516
   1517void dispc_ovl_compute_fifo_thresholds(struct dispc_device *dispc,
   1518				       enum omap_plane_id plane,
   1519				       u32 *fifo_low, u32 *fifo_high,
   1520				       bool use_fifomerge, bool manual_update)
   1521{
   1522	/*
   1523	 * All sizes are in bytes. Both the buffer and burst are made of
   1524	 * buffer_units, and the fifo thresholds must be buffer_unit aligned.
   1525	 */
   1526	unsigned int buf_unit = dispc->feat->buffer_size_unit;
   1527	unsigned int ovl_fifo_size, total_fifo_size, burst_size;
   1528	int i;
   1529
   1530	burst_size = dispc_ovl_get_burst_size(dispc, plane);
   1531	ovl_fifo_size = dispc_ovl_get_fifo_size(dispc, plane);
   1532
   1533	if (use_fifomerge) {
   1534		total_fifo_size = 0;
   1535		for (i = 0; i < dispc_get_num_ovls(dispc); ++i)
   1536			total_fifo_size += dispc_ovl_get_fifo_size(dispc, i);
   1537	} else {
   1538		total_fifo_size = ovl_fifo_size;
   1539	}
   1540
   1541	/*
   1542	 * We use the same low threshold for both fifomerge and non-fifomerge
   1543	 * cases, but for fifomerge we calculate the high threshold using the
   1544	 * combined fifo size
   1545	 */
   1546
   1547	if (manual_update && dispc_has_feature(dispc, FEAT_OMAP3_DSI_FIFO_BUG)) {
   1548		*fifo_low = ovl_fifo_size - burst_size * 2;
   1549		*fifo_high = total_fifo_size - burst_size;
   1550	} else if (plane == OMAP_DSS_WB) {
   1551		/*
   1552		 * Most optimal configuration for writeback is to push out data
   1553		 * to the interconnect the moment writeback pushes enough pixels
   1554		 * in the FIFO to form a burst
   1555		 */
   1556		*fifo_low = 0;
   1557		*fifo_high = burst_size;
   1558	} else {
   1559		*fifo_low = ovl_fifo_size - burst_size;
   1560		*fifo_high = total_fifo_size - buf_unit;
   1561	}
   1562}
   1563
   1564static void dispc_ovl_set_mflag(struct dispc_device *dispc,
   1565				enum omap_plane_id plane, bool enable)
   1566{
   1567	int bit;
   1568
   1569	if (plane == OMAP_DSS_GFX)
   1570		bit = 14;
   1571	else
   1572		bit = 23;
   1573
   1574	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit);
   1575}
   1576
   1577static void dispc_ovl_set_mflag_threshold(struct dispc_device *dispc,
   1578					  enum omap_plane_id plane,
   1579					  int low, int high)
   1580{
   1581	dispc_write_reg(dispc, DISPC_OVL_MFLAG_THRESHOLD(plane),
   1582		FLD_VAL(high, 31, 16) |	FLD_VAL(low, 15, 0));
   1583}
   1584
   1585static void dispc_init_mflag(struct dispc_device *dispc)
   1586{
   1587	int i;
   1588
   1589	/*
   1590	 * HACK: NV12 color format and MFLAG seem to have problems working
   1591	 * together: using two displays, and having an NV12 overlay on one of
   1592	 * the displays will cause underflows/synclosts when MFLAG_CTRL=2.
   1593	 * Changing MFLAG thresholds and PRELOAD to certain values seem to
   1594	 * remove the errors, but there doesn't seem to be a clear logic on
   1595	 * which values work and which not.
   1596	 *
   1597	 * As a work-around, set force MFLAG to always on.
   1598	 */
   1599	dispc_write_reg(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE,
   1600		(1 << 0) |	/* MFLAG_CTRL = force always on */
   1601		(0 << 2));	/* MFLAG_START = disable */
   1602
   1603	for (i = 0; i < dispc_get_num_ovls(dispc); ++i) {
   1604		u32 size = dispc_ovl_get_fifo_size(dispc, i);
   1605		u32 unit = dispc->feat->buffer_size_unit;
   1606		u32 low, high;
   1607
   1608		dispc_ovl_set_mflag(dispc, i, true);
   1609
   1610		/*
   1611		 * Simulation team suggests below thesholds:
   1612		 * HT = fifosize * 5 / 8;
   1613		 * LT = fifosize * 4 / 8;
   1614		 */
   1615
   1616		low = size * 4 / 8 / unit;
   1617		high = size * 5 / 8 / unit;
   1618
   1619		dispc_ovl_set_mflag_threshold(dispc, i, low, high);
   1620	}
   1621
   1622	if (dispc->feat->has_writeback) {
   1623		u32 size = dispc_ovl_get_fifo_size(dispc, OMAP_DSS_WB);
   1624		u32 unit = dispc->feat->buffer_size_unit;
   1625		u32 low, high;
   1626
   1627		dispc_ovl_set_mflag(dispc, OMAP_DSS_WB, true);
   1628
   1629		/*
   1630		 * Simulation team suggests below thesholds:
   1631		 * HT = fifosize * 5 / 8;
   1632		 * LT = fifosize * 4 / 8;
   1633		 */
   1634
   1635		low = size * 4 / 8 / unit;
   1636		high = size * 5 / 8 / unit;
   1637
   1638		dispc_ovl_set_mflag_threshold(dispc, OMAP_DSS_WB, low, high);
   1639	}
   1640}
   1641
   1642static void dispc_ovl_set_fir(struct dispc_device *dispc,
   1643			      enum omap_plane_id plane,
   1644			      int hinc, int vinc,
   1645			      enum omap_color_component color_comp)
   1646{
   1647	u32 val;
   1648
   1649	if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
   1650		u8 hinc_start, hinc_end, vinc_start, vinc_end;
   1651
   1652		dispc_get_reg_field(dispc, FEAT_REG_FIRHINC,
   1653				    &hinc_start, &hinc_end);
   1654		dispc_get_reg_field(dispc, FEAT_REG_FIRVINC,
   1655				    &vinc_start, &vinc_end);
   1656		val = FLD_VAL(vinc, vinc_start, vinc_end) |
   1657				FLD_VAL(hinc, hinc_start, hinc_end);
   1658
   1659		dispc_write_reg(dispc, DISPC_OVL_FIR(plane), val);
   1660	} else {
   1661		val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
   1662		dispc_write_reg(dispc, DISPC_OVL_FIR2(plane), val);
   1663	}
   1664}
   1665
   1666static void dispc_ovl_set_vid_accu0(struct dispc_device *dispc,
   1667				    enum omap_plane_id plane, int haccu,
   1668				    int vaccu)
   1669{
   1670	u32 val;
   1671	u8 hor_start, hor_end, vert_start, vert_end;
   1672
   1673	dispc_get_reg_field(dispc, FEAT_REG_HORIZONTALACCU,
   1674			    &hor_start, &hor_end);
   1675	dispc_get_reg_field(dispc, FEAT_REG_VERTICALACCU,
   1676			    &vert_start, &vert_end);
   1677
   1678	val = FLD_VAL(vaccu, vert_start, vert_end) |
   1679			FLD_VAL(haccu, hor_start, hor_end);
   1680
   1681	dispc_write_reg(dispc, DISPC_OVL_ACCU0(plane), val);
   1682}
   1683
   1684static void dispc_ovl_set_vid_accu1(struct dispc_device *dispc,
   1685				    enum omap_plane_id plane, int haccu,
   1686				    int vaccu)
   1687{
   1688	u32 val;
   1689	u8 hor_start, hor_end, vert_start, vert_end;
   1690
   1691	dispc_get_reg_field(dispc, FEAT_REG_HORIZONTALACCU,
   1692			    &hor_start, &hor_end);
   1693	dispc_get_reg_field(dispc, FEAT_REG_VERTICALACCU,
   1694			    &vert_start, &vert_end);
   1695
   1696	val = FLD_VAL(vaccu, vert_start, vert_end) |
   1697			FLD_VAL(haccu, hor_start, hor_end);
   1698
   1699	dispc_write_reg(dispc, DISPC_OVL_ACCU1(plane), val);
   1700}
   1701
   1702static void dispc_ovl_set_vid_accu2_0(struct dispc_device *dispc,
   1703				      enum omap_plane_id plane, int haccu,
   1704				      int vaccu)
   1705{
   1706	u32 val;
   1707
   1708	val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
   1709	dispc_write_reg(dispc, DISPC_OVL_ACCU2_0(plane), val);
   1710}
   1711
   1712static void dispc_ovl_set_vid_accu2_1(struct dispc_device *dispc,
   1713				      enum omap_plane_id plane, int haccu,
   1714				      int vaccu)
   1715{
   1716	u32 val;
   1717
   1718	val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
   1719	dispc_write_reg(dispc, DISPC_OVL_ACCU2_1(plane), val);
   1720}
   1721
   1722static void dispc_ovl_set_scale_param(struct dispc_device *dispc,
   1723				      enum omap_plane_id plane,
   1724				      u16 orig_width, u16 orig_height,
   1725				      u16 out_width, u16 out_height,
   1726				      bool five_taps, u8 rotation,
   1727				      enum omap_color_component color_comp)
   1728{
   1729	int fir_hinc, fir_vinc;
   1730
   1731	fir_hinc = 1024 * orig_width / out_width;
   1732	fir_vinc = 1024 * orig_height / out_height;
   1733
   1734	dispc_ovl_set_scale_coef(dispc, plane, fir_hinc, fir_vinc, five_taps,
   1735				 color_comp);
   1736	dispc_ovl_set_fir(dispc, plane, fir_hinc, fir_vinc, color_comp);
   1737}
   1738
   1739static void dispc_ovl_set_accu_uv(struct dispc_device *dispc,
   1740				  enum omap_plane_id plane,
   1741				  u16 orig_width, u16 orig_height,
   1742				  u16 out_width, u16 out_height,
   1743				  bool ilace, u32 fourcc, u8 rotation)
   1744{
   1745	int h_accu2_0, h_accu2_1;
   1746	int v_accu2_0, v_accu2_1;
   1747	int chroma_hinc, chroma_vinc;
   1748	int idx;
   1749
   1750	struct accu {
   1751		s8 h0_m, h0_n;
   1752		s8 h1_m, h1_n;
   1753		s8 v0_m, v0_n;
   1754		s8 v1_m, v1_n;
   1755	};
   1756
   1757	const struct accu *accu_table;
   1758	const struct accu *accu_val;
   1759
   1760	static const struct accu accu_nv12[4] = {
   1761		{  0, 1,  0, 1 , -1, 2, 0, 1 },
   1762		{  1, 2, -3, 4 ,  0, 1, 0, 1 },
   1763		{ -1, 1,  0, 1 , -1, 2, 0, 1 },
   1764		{ -1, 2, -1, 2 , -1, 1, 0, 1 },
   1765	};
   1766
   1767	static const struct accu accu_nv12_ilace[4] = {
   1768		{  0, 1,  0, 1 , -3, 4, -1, 4 },
   1769		{ -1, 4, -3, 4 ,  0, 1,  0, 1 },
   1770		{ -1, 1,  0, 1 , -1, 4, -3, 4 },
   1771		{ -3, 4, -3, 4 , -1, 1,  0, 1 },
   1772	};
   1773
   1774	static const struct accu accu_yuv[4] = {
   1775		{  0, 1, 0, 1,  0, 1, 0, 1 },
   1776		{  0, 1, 0, 1,  0, 1, 0, 1 },
   1777		{ -1, 1, 0, 1,  0, 1, 0, 1 },
   1778		{  0, 1, 0, 1, -1, 1, 0, 1 },
   1779	};
   1780
   1781	/* Note: DSS HW rotates clockwise, DRM_MODE_ROTATE_* counter-clockwise */
   1782	switch (rotation & DRM_MODE_ROTATE_MASK) {
   1783	default:
   1784	case DRM_MODE_ROTATE_0:
   1785		idx = 0;
   1786		break;
   1787	case DRM_MODE_ROTATE_90:
   1788		idx = 3;
   1789		break;
   1790	case DRM_MODE_ROTATE_180:
   1791		idx = 2;
   1792		break;
   1793	case DRM_MODE_ROTATE_270:
   1794		idx = 1;
   1795		break;
   1796	}
   1797
   1798	switch (fourcc) {
   1799	case DRM_FORMAT_NV12:
   1800		if (ilace)
   1801			accu_table = accu_nv12_ilace;
   1802		else
   1803			accu_table = accu_nv12;
   1804		break;
   1805	case DRM_FORMAT_YUYV:
   1806	case DRM_FORMAT_UYVY:
   1807		accu_table = accu_yuv;
   1808		break;
   1809	default:
   1810		BUG();
   1811		return;
   1812	}
   1813
   1814	accu_val = &accu_table[idx];
   1815
   1816	chroma_hinc = 1024 * orig_width / out_width;
   1817	chroma_vinc = 1024 * orig_height / out_height;
   1818
   1819	h_accu2_0 = (accu_val->h0_m * chroma_hinc / accu_val->h0_n) % 1024;
   1820	h_accu2_1 = (accu_val->h1_m * chroma_hinc / accu_val->h1_n) % 1024;
   1821	v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024;
   1822	v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024;
   1823
   1824	dispc_ovl_set_vid_accu2_0(dispc, plane, h_accu2_0, v_accu2_0);
   1825	dispc_ovl_set_vid_accu2_1(dispc, plane, h_accu2_1, v_accu2_1);
   1826}
   1827
   1828static void dispc_ovl_set_scaling_common(struct dispc_device *dispc,
   1829					 enum omap_plane_id plane,
   1830					 u16 orig_width, u16 orig_height,
   1831					 u16 out_width, u16 out_height,
   1832					 bool ilace, bool five_taps,
   1833					 bool fieldmode, u32 fourcc,
   1834					 u8 rotation)
   1835{
   1836	int accu0 = 0;
   1837	int accu1 = 0;
   1838	u32 l;
   1839
   1840	dispc_ovl_set_scale_param(dispc, plane, orig_width, orig_height,
   1841				  out_width, out_height, five_taps,
   1842				  rotation, DISPC_COLOR_COMPONENT_RGB_Y);
   1843	l = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane));
   1844
   1845	/* RESIZEENABLE and VERTICALTAPS */
   1846	l &= ~((0x3 << 5) | (0x1 << 21));
   1847	l |= (orig_width != out_width) ? (1 << 5) : 0;
   1848	l |= (orig_height != out_height) ? (1 << 6) : 0;
   1849	l |= five_taps ? (1 << 21) : 0;
   1850
   1851	/* VRESIZECONF and HRESIZECONF */
   1852	if (dispc_has_feature(dispc, FEAT_RESIZECONF)) {
   1853		l &= ~(0x3 << 7);
   1854		l |= (orig_width <= out_width) ? 0 : (1 << 7);
   1855		l |= (orig_height <= out_height) ? 0 : (1 << 8);
   1856	}
   1857
   1858	/* LINEBUFFERSPLIT */
   1859	if (dispc_has_feature(dispc, FEAT_LINEBUFFERSPLIT)) {
   1860		l &= ~(0x1 << 22);
   1861		l |= five_taps ? (1 << 22) : 0;
   1862	}
   1863
   1864	dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), l);
   1865
   1866	/*
   1867	 * field 0 = even field = bottom field
   1868	 * field 1 = odd field = top field
   1869	 */
   1870	if (ilace && !fieldmode) {
   1871		accu1 = 0;
   1872		accu0 = ((1024 * orig_height / out_height) / 2) & 0x3ff;
   1873		if (accu0 >= 1024/2) {
   1874			accu1 = 1024/2;
   1875			accu0 -= accu1;
   1876		}
   1877	}
   1878
   1879	dispc_ovl_set_vid_accu0(dispc, plane, 0, accu0);
   1880	dispc_ovl_set_vid_accu1(dispc, plane, 0, accu1);
   1881}
   1882
   1883static void dispc_ovl_set_scaling_uv(struct dispc_device *dispc,
   1884				     enum omap_plane_id plane,
   1885				     u16 orig_width, u16 orig_height,
   1886				     u16 out_width, u16 out_height,
   1887				     bool ilace, bool five_taps,
   1888				     bool fieldmode, u32 fourcc,
   1889				     u8 rotation)
   1890{
   1891	int scale_x = out_width != orig_width;
   1892	int scale_y = out_height != orig_height;
   1893	bool chroma_upscale = plane != OMAP_DSS_WB;
   1894	const struct drm_format_info *info;
   1895
   1896	info = drm_format_info(fourcc);
   1897
   1898	if (!dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE))
   1899		return;
   1900
   1901	if (!info->is_yuv) {
   1902		/* reset chroma resampling for RGB formats  */
   1903		if (plane != OMAP_DSS_WB)
   1904			REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane),
   1905				    0, 8, 8);
   1906		return;
   1907	}
   1908
   1909	dispc_ovl_set_accu_uv(dispc, plane, orig_width, orig_height, out_width,
   1910			      out_height, ilace, fourcc, rotation);
   1911
   1912	switch (fourcc) {
   1913	case DRM_FORMAT_NV12:
   1914		if (chroma_upscale) {
   1915			/* UV is subsampled by 2 horizontally and vertically */
   1916			orig_height >>= 1;
   1917			orig_width >>= 1;
   1918		} else {
   1919			/* UV is downsampled by 2 horizontally and vertically */
   1920			orig_height <<= 1;
   1921			orig_width <<= 1;
   1922		}
   1923
   1924		break;
   1925	case DRM_FORMAT_YUYV:
   1926	case DRM_FORMAT_UYVY:
   1927		/* For YUV422 with 90/270 rotation, we don't upsample chroma */
   1928		if (!drm_rotation_90_or_270(rotation)) {
   1929			if (chroma_upscale)
   1930				/* UV is subsampled by 2 horizontally */
   1931				orig_width >>= 1;
   1932			else
   1933				/* UV is downsampled by 2 horizontally */
   1934				orig_width <<= 1;
   1935		}
   1936
   1937		/* must use FIR for YUV422 if rotated */
   1938		if ((rotation & DRM_MODE_ROTATE_MASK) != DRM_MODE_ROTATE_0)
   1939			scale_x = scale_y = true;
   1940
   1941		break;
   1942	default:
   1943		BUG();
   1944		return;
   1945	}
   1946
   1947	if (out_width != orig_width)
   1948		scale_x = true;
   1949	if (out_height != orig_height)
   1950		scale_y = true;
   1951
   1952	dispc_ovl_set_scale_param(dispc, plane, orig_width, orig_height,
   1953				  out_width, out_height, five_taps,
   1954				  rotation, DISPC_COLOR_COMPONENT_UV);
   1955
   1956	if (plane != OMAP_DSS_WB)
   1957		REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane),
   1958			(scale_x || scale_y) ? 1 : 0, 8, 8);
   1959
   1960	/* set H scaling */
   1961	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5);
   1962	/* set V scaling */
   1963	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6);
   1964}
   1965
   1966static void dispc_ovl_set_scaling(struct dispc_device *dispc,
   1967				  enum omap_plane_id plane,
   1968				  u16 orig_width, u16 orig_height,
   1969				  u16 out_width, u16 out_height,
   1970				  bool ilace, bool five_taps,
   1971				  bool fieldmode, u32 fourcc,
   1972				  u8 rotation)
   1973{
   1974	BUG_ON(plane == OMAP_DSS_GFX);
   1975
   1976	dispc_ovl_set_scaling_common(dispc, plane, orig_width, orig_height,
   1977				     out_width, out_height, ilace, five_taps,
   1978				     fieldmode, fourcc, rotation);
   1979
   1980	dispc_ovl_set_scaling_uv(dispc, plane, orig_width, orig_height,
   1981				 out_width, out_height, ilace, five_taps,
   1982				 fieldmode, fourcc, rotation);
   1983}
   1984
   1985static void dispc_ovl_set_rotation_attrs(struct dispc_device *dispc,
   1986					 enum omap_plane_id plane, u8 rotation,
   1987					 enum omap_dss_rotation_type rotation_type,
   1988					 u32 fourcc)
   1989{
   1990	bool row_repeat = false;
   1991	int vidrot = 0;
   1992
   1993	/* Note: DSS HW rotates clockwise, DRM_MODE_ROTATE_* counter-clockwise */
   1994	if (fourcc == DRM_FORMAT_YUYV || fourcc == DRM_FORMAT_UYVY) {
   1995
   1996		if (rotation & DRM_MODE_REFLECT_X) {
   1997			switch (rotation & DRM_MODE_ROTATE_MASK) {
   1998			case DRM_MODE_ROTATE_0:
   1999				vidrot = 2;
   2000				break;
   2001			case DRM_MODE_ROTATE_90:
   2002				vidrot = 1;
   2003				break;
   2004			case DRM_MODE_ROTATE_180:
   2005				vidrot = 0;
   2006				break;
   2007			case DRM_MODE_ROTATE_270:
   2008				vidrot = 3;
   2009				break;
   2010			}
   2011		} else {
   2012			switch (rotation & DRM_MODE_ROTATE_MASK) {
   2013			case DRM_MODE_ROTATE_0:
   2014				vidrot = 0;
   2015				break;
   2016			case DRM_MODE_ROTATE_90:
   2017				vidrot = 3;
   2018				break;
   2019			case DRM_MODE_ROTATE_180:
   2020				vidrot = 2;
   2021				break;
   2022			case DRM_MODE_ROTATE_270:
   2023				vidrot = 1;
   2024				break;
   2025			}
   2026		}
   2027
   2028		if (drm_rotation_90_or_270(rotation))
   2029			row_repeat = true;
   2030		else
   2031			row_repeat = false;
   2032	}
   2033
   2034	/*
   2035	 * OMAP4/5 Errata i631:
   2036	 * NV12 in 1D mode must use ROTATION=1. Otherwise DSS will fetch extra
   2037	 * rows beyond the framebuffer, which may cause OCP error.
   2038	 */
   2039	if (fourcc == DRM_FORMAT_NV12 && rotation_type != OMAP_DSS_ROT_TILER)
   2040		vidrot = 1;
   2041
   2042	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12);
   2043	if (dispc_has_feature(dispc, FEAT_ROWREPEATENABLE))
   2044		REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane),
   2045			row_repeat ? 1 : 0, 18, 18);
   2046
   2047	if (dispc_ovl_color_mode_supported(dispc, plane, DRM_FORMAT_NV12)) {
   2048		bool doublestride =
   2049			fourcc == DRM_FORMAT_NV12 &&
   2050			rotation_type == OMAP_DSS_ROT_TILER &&
   2051			!drm_rotation_90_or_270(rotation);
   2052
   2053		/* DOUBLESTRIDE */
   2054		REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane),
   2055			    doublestride, 22, 22);
   2056	}
   2057}
   2058
   2059static int color_mode_to_bpp(u32 fourcc)
   2060{
   2061	switch (fourcc) {
   2062	case DRM_FORMAT_NV12:
   2063		return 8;
   2064	case DRM_FORMAT_RGBX4444:
   2065	case DRM_FORMAT_RGB565:
   2066	case DRM_FORMAT_ARGB4444:
   2067	case DRM_FORMAT_YUYV:
   2068	case DRM_FORMAT_UYVY:
   2069	case DRM_FORMAT_RGBA4444:
   2070	case DRM_FORMAT_XRGB4444:
   2071	case DRM_FORMAT_ARGB1555:
   2072	case DRM_FORMAT_XRGB1555:
   2073		return 16;
   2074	case DRM_FORMAT_RGB888:
   2075		return 24;
   2076	case DRM_FORMAT_XRGB8888:
   2077	case DRM_FORMAT_ARGB8888:
   2078	case DRM_FORMAT_RGBA8888:
   2079	case DRM_FORMAT_RGBX8888:
   2080		return 32;
   2081	default:
   2082		BUG();
   2083		return 0;
   2084	}
   2085}
   2086
   2087static s32 pixinc(int pixels, u8 ps)
   2088{
   2089	if (pixels == 1)
   2090		return 1;
   2091	else if (pixels > 1)
   2092		return 1 + (pixels - 1) * ps;
   2093	else if (pixels < 0)
   2094		return 1 - (-pixels + 1) * ps;
   2095
   2096	BUG();
   2097}
   2098
   2099static void calc_offset(u16 screen_width, u16 width,
   2100		u32 fourcc, bool fieldmode, unsigned int field_offset,
   2101		unsigned int *offset0, unsigned int *offset1,
   2102		s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim,
   2103		enum omap_dss_rotation_type rotation_type, u8 rotation)
   2104{
   2105	u8 ps;
   2106
   2107	ps = color_mode_to_bpp(fourcc) / 8;
   2108
   2109	DSSDBG("scrw %d, width %d\n", screen_width, width);
   2110
   2111	if (rotation_type == OMAP_DSS_ROT_TILER &&
   2112	    (fourcc == DRM_FORMAT_UYVY || fourcc == DRM_FORMAT_YUYV) &&
   2113	    drm_rotation_90_or_270(rotation)) {
   2114		/*
   2115		 * HACK: ROW_INC needs to be calculated with TILER units.
   2116		 * We get such 'screen_width' that multiplying it with the
   2117		 * YUV422 pixel size gives the correct TILER container width.
   2118		 * However, 'width' is in pixels and multiplying it with YUV422
   2119		 * pixel size gives incorrect result. We thus multiply it here
   2120		 * with 2 to match the 32 bit TILER unit size.
   2121		 */
   2122		width *= 2;
   2123	}
   2124
   2125	/*
   2126	 * field 0 = even field = bottom field
   2127	 * field 1 = odd field = top field
   2128	 */
   2129	*offset0 = field_offset * screen_width * ps;
   2130	*offset1 = 0;
   2131
   2132	*row_inc = pixinc(1 + (y_predecim * screen_width - width * x_predecim) +
   2133			(fieldmode ? screen_width : 0), ps);
   2134	if (fourcc == DRM_FORMAT_YUYV || fourcc == DRM_FORMAT_UYVY)
   2135		*pix_inc = pixinc(x_predecim, 2 * ps);
   2136	else
   2137		*pix_inc = pixinc(x_predecim, ps);
   2138}
   2139
   2140/*
   2141 * This function is used to avoid synclosts in OMAP3, because of some
   2142 * undocumented horizontal position and timing related limitations.
   2143 */
   2144static int check_horiz_timing_omap3(unsigned long pclk, unsigned long lclk,
   2145		const struct videomode *vm, u16 pos_x,
   2146		u16 width, u16 height, u16 out_width, u16 out_height,
   2147		bool five_taps)
   2148{
   2149	const int ds = DIV_ROUND_UP(height, out_height);
   2150	unsigned long nonactive;
   2151	static const u8 limits[3] = { 8, 10, 20 };
   2152	u64 val, blank;
   2153	int i;
   2154
   2155	nonactive = vm->hactive + vm->hfront_porch + vm->hsync_len +
   2156		    vm->hback_porch - out_width;
   2157
   2158	i = 0;
   2159	if (out_height < height)
   2160		i++;
   2161	if (out_width < width)
   2162		i++;
   2163	blank = div_u64((u64)(vm->hback_porch + vm->hsync_len + vm->hfront_porch) *
   2164			lclk, pclk);
   2165	DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]);
   2166	if (blank <= limits[i])
   2167		return -EINVAL;
   2168
   2169	/* FIXME add checks for 3-tap filter once the limitations are known */
   2170	if (!five_taps)
   2171		return 0;
   2172
   2173	/*
   2174	 * Pixel data should be prepared before visible display point starts.
   2175	 * So, atleast DS-2 lines must have already been fetched by DISPC
   2176	 * during nonactive - pos_x period.
   2177	 */
   2178	val = div_u64((u64)(nonactive - pos_x) * lclk, pclk);
   2179	DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n",
   2180		val, max(0, ds - 2) * width);
   2181	if (val < max(0, ds - 2) * width)
   2182		return -EINVAL;
   2183
   2184	/*
   2185	 * All lines need to be refilled during the nonactive period of which
   2186	 * only one line can be loaded during the active period. So, atleast
   2187	 * DS - 1 lines should be loaded during nonactive period.
   2188	 */
   2189	val =  div_u64((u64)nonactive * lclk, pclk);
   2190	DSSDBG("nonactive * pcd  = %llu, max(0, DS - 1) * width = %d\n",
   2191		val, max(0, ds - 1) * width);
   2192	if (val < max(0, ds - 1) * width)
   2193		return -EINVAL;
   2194
   2195	return 0;
   2196}
   2197
   2198static unsigned long calc_core_clk_five_taps(unsigned long pclk,
   2199		const struct videomode *vm, u16 width,
   2200		u16 height, u16 out_width, u16 out_height,
   2201		u32 fourcc)
   2202{
   2203	u32 core_clk = 0;
   2204	u64 tmp;
   2205
   2206	if (height <= out_height && width <= out_width)
   2207		return (unsigned long) pclk;
   2208
   2209	if (height > out_height) {
   2210		unsigned int ppl = vm->hactive;
   2211
   2212		tmp = (u64)pclk * height * out_width;
   2213		do_div(tmp, 2 * out_height * ppl);
   2214		core_clk = tmp;
   2215
   2216		if (height > 2 * out_height) {
   2217			if (ppl == out_width)
   2218				return 0;
   2219
   2220			tmp = (u64)pclk * (height - 2 * out_height) * out_width;
   2221			do_div(tmp, 2 * out_height * (ppl - out_width));
   2222			core_clk = max_t(u32, core_clk, tmp);
   2223		}
   2224	}
   2225
   2226	if (width > out_width) {
   2227		tmp = (u64)pclk * width;
   2228		do_div(tmp, out_width);
   2229		core_clk = max_t(u32, core_clk, tmp);
   2230
   2231		if (fourcc == DRM_FORMAT_XRGB8888)
   2232			core_clk <<= 1;
   2233	}
   2234
   2235	return core_clk;
   2236}
   2237
   2238static unsigned long calc_core_clk_24xx(unsigned long pclk, u16 width,
   2239		u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
   2240{
   2241	if (height > out_height && width > out_width)
   2242		return pclk * 4;
   2243	else
   2244		return pclk * 2;
   2245}
   2246
   2247static unsigned long calc_core_clk_34xx(unsigned long pclk, u16 width,
   2248		u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
   2249{
   2250	unsigned int hf, vf;
   2251
   2252	/*
   2253	 * FIXME how to determine the 'A' factor
   2254	 * for the no downscaling case ?
   2255	 */
   2256
   2257	if (width > 3 * out_width)
   2258		hf = 4;
   2259	else if (width > 2 * out_width)
   2260		hf = 3;
   2261	else if (width > out_width)
   2262		hf = 2;
   2263	else
   2264		hf = 1;
   2265	if (height > out_height)
   2266		vf = 2;
   2267	else
   2268		vf = 1;
   2269
   2270	return pclk * vf * hf;
   2271}
   2272
   2273static unsigned long calc_core_clk_44xx(unsigned long pclk, u16 width,
   2274		u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
   2275{
   2276	/*
   2277	 * If the overlay/writeback is in mem to mem mode, there are no
   2278	 * downscaling limitations with respect to pixel clock, return 1 as
   2279	 * required core clock to represent that we have sufficient enough
   2280	 * core clock to do maximum downscaling
   2281	 */
   2282	if (mem_to_mem)
   2283		return 1;
   2284
   2285	if (width > out_width)
   2286		return DIV_ROUND_UP(pclk, out_width) * width;
   2287	else
   2288		return pclk;
   2289}
   2290
   2291static int dispc_ovl_calc_scaling_24xx(struct dispc_device *dispc,
   2292				       unsigned long pclk, unsigned long lclk,
   2293				       const struct videomode *vm,
   2294				       u16 width, u16 height,
   2295				       u16 out_width, u16 out_height,
   2296				       u32 fourcc, bool *five_taps,
   2297				       int *x_predecim, int *y_predecim,
   2298				       int *decim_x, int *decim_y,
   2299				       u16 pos_x, unsigned long *core_clk,
   2300				       bool mem_to_mem)
   2301{
   2302	int error;
   2303	u16 in_width, in_height;
   2304	int min_factor = min(*decim_x, *decim_y);
   2305	const int maxsinglelinewidth = dispc->feat->max_line_width;
   2306
   2307	*five_taps = false;
   2308
   2309	do {
   2310		in_height = height / *decim_y;
   2311		in_width = width / *decim_x;
   2312		*core_clk = dispc->feat->calc_core_clk(pclk, in_width,
   2313				in_height, out_width, out_height, mem_to_mem);
   2314		error = (in_width > maxsinglelinewidth || !*core_clk ||
   2315			*core_clk > dispc_core_clk_rate(dispc));
   2316		if (error) {
   2317			if (*decim_x == *decim_y) {
   2318				*decim_x = min_factor;
   2319				++*decim_y;
   2320			} else {
   2321				swap(*decim_x, *decim_y);
   2322				if (*decim_x < *decim_y)
   2323					++*decim_x;
   2324			}
   2325		}
   2326	} while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
   2327
   2328	if (error) {
   2329		DSSERR("failed to find scaling settings\n");
   2330		return -EINVAL;
   2331	}
   2332
   2333	if (in_width > maxsinglelinewidth) {
   2334		DSSERR("Cannot scale max input width exceeded\n");
   2335		return -EINVAL;
   2336	}
   2337	return 0;
   2338}
   2339
   2340static int dispc_ovl_calc_scaling_34xx(struct dispc_device *dispc,
   2341				       unsigned long pclk, unsigned long lclk,
   2342				       const struct videomode *vm,
   2343				       u16 width, u16 height,
   2344				       u16 out_width, u16 out_height,
   2345				       u32 fourcc, bool *five_taps,
   2346				       int *x_predecim, int *y_predecim,
   2347				       int *decim_x, int *decim_y,
   2348				       u16 pos_x, unsigned long *core_clk,
   2349				       bool mem_to_mem)
   2350{
   2351	int error;
   2352	u16 in_width, in_height;
   2353	const int maxsinglelinewidth = dispc->feat->max_line_width;
   2354
   2355	do {
   2356		in_height = height / *decim_y;
   2357		in_width = width / *decim_x;
   2358		*five_taps = in_height > out_height;
   2359
   2360		if (in_width > maxsinglelinewidth)
   2361			if (in_height > out_height &&
   2362						in_height < out_height * 2)
   2363				*five_taps = false;
   2364again:
   2365		if (*five_taps)
   2366			*core_clk = calc_core_clk_five_taps(pclk, vm,
   2367						in_width, in_height, out_width,
   2368						out_height, fourcc);
   2369		else
   2370			*core_clk = dispc->feat->calc_core_clk(pclk, in_width,
   2371					in_height, out_width, out_height,
   2372					mem_to_mem);
   2373
   2374		error = check_horiz_timing_omap3(pclk, lclk, vm,
   2375				pos_x, in_width, in_height, out_width,
   2376				out_height, *five_taps);
   2377		if (error && *five_taps) {
   2378			*five_taps = false;
   2379			goto again;
   2380		}
   2381
   2382		error = (error || in_width > maxsinglelinewidth * 2 ||
   2383			(in_width > maxsinglelinewidth && *five_taps) ||
   2384			!*core_clk || *core_clk > dispc_core_clk_rate(dispc));
   2385
   2386		if (!error) {
   2387			/* verify that we're inside the limits of scaler */
   2388			if (in_width / 4 > out_width)
   2389					error = 1;
   2390
   2391			if (*five_taps) {
   2392				if (in_height / 4 > out_height)
   2393					error = 1;
   2394			} else {
   2395				if (in_height / 2 > out_height)
   2396					error = 1;
   2397			}
   2398		}
   2399
   2400		if (error)
   2401			++*decim_y;
   2402	} while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
   2403
   2404	if (error) {
   2405		DSSERR("failed to find scaling settings\n");
   2406		return -EINVAL;
   2407	}
   2408
   2409	if (check_horiz_timing_omap3(pclk, lclk, vm, pos_x, in_width,
   2410				in_height, out_width, out_height, *five_taps)) {
   2411			DSSERR("horizontal timing too tight\n");
   2412			return -EINVAL;
   2413	}
   2414
   2415	if (in_width > (maxsinglelinewidth * 2)) {
   2416		DSSERR("Cannot setup scaling\n");
   2417		DSSERR("width exceeds maximum width possible\n");
   2418		return -EINVAL;
   2419	}
   2420
   2421	if (in_width > maxsinglelinewidth && *five_taps) {
   2422		DSSERR("cannot setup scaling with five taps\n");
   2423		return -EINVAL;
   2424	}
   2425	return 0;
   2426}
   2427
   2428static int dispc_ovl_calc_scaling_44xx(struct dispc_device *dispc,
   2429				       unsigned long pclk, unsigned long lclk,
   2430				       const struct videomode *vm,
   2431				       u16 width, u16 height,
   2432				       u16 out_width, u16 out_height,
   2433				       u32 fourcc, bool *five_taps,
   2434				       int *x_predecim, int *y_predecim,
   2435				       int *decim_x, int *decim_y,
   2436				       u16 pos_x, unsigned long *core_clk,
   2437				       bool mem_to_mem)
   2438{
   2439	u16 in_width, in_width_max;
   2440	int decim_x_min = *decim_x;
   2441	u16 in_height = height / *decim_y;
   2442	const int maxsinglelinewidth = dispc->feat->max_line_width;
   2443	const int maxdownscale = dispc->feat->max_downscale;
   2444
   2445	if (mem_to_mem) {
   2446		in_width_max = out_width * maxdownscale;
   2447	} else {
   2448		in_width_max = dispc_core_clk_rate(dispc)
   2449			     / DIV_ROUND_UP(pclk, out_width);
   2450	}
   2451
   2452	*decim_x = DIV_ROUND_UP(width, in_width_max);
   2453
   2454	*decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min;
   2455	if (*decim_x > *x_predecim)
   2456		return -EINVAL;
   2457
   2458	do {
   2459		in_width = width / *decim_x;
   2460	} while (*decim_x <= *x_predecim &&
   2461			in_width > maxsinglelinewidth && ++*decim_x);
   2462
   2463	if (in_width > maxsinglelinewidth) {
   2464		DSSERR("Cannot scale width exceeds max line width\n");
   2465		return -EINVAL;
   2466	}
   2467
   2468	if (*decim_x > 4 && fourcc != DRM_FORMAT_NV12) {
   2469		/*
   2470		 * Let's disable all scaling that requires horizontal
   2471		 * decimation with higher factor than 4, until we have
   2472		 * better estimates of what we can and can not
   2473		 * do. However, NV12 color format appears to work Ok
   2474		 * with all decimation factors.
   2475		 *
   2476		 * When decimating horizontally by more that 4 the dss
   2477		 * is not able to fetch the data in burst mode. When
   2478		 * this happens it is hard to tell if there enough
   2479		 * bandwidth. Despite what theory says this appears to
   2480		 * be true also for 16-bit color formats.
   2481		 */
   2482		DSSERR("Not enough bandwidth, too much downscaling (x-decimation factor %d > 4)\n", *decim_x);
   2483
   2484		return -EINVAL;
   2485	}
   2486
   2487	*core_clk = dispc->feat->calc_core_clk(pclk, in_width, in_height,
   2488				out_width, out_height, mem_to_mem);
   2489	return 0;
   2490}
   2491
   2492enum omap_overlay_caps dispc_ovl_get_caps(struct dispc_device *dispc, enum omap_plane_id plane)
   2493{
   2494	return dispc->feat->overlay_caps[plane];
   2495}
   2496
   2497#define DIV_FRAC(dividend, divisor) \
   2498	((dividend) * 100 / (divisor) - ((dividend) / (divisor) * 100))
   2499
   2500static int dispc_ovl_calc_scaling(struct dispc_device *dispc,
   2501				  enum omap_plane_id plane,
   2502				  unsigned long pclk, unsigned long lclk,
   2503				  enum omap_overlay_caps caps,
   2504				  const struct videomode *vm,
   2505				  u16 width, u16 height,
   2506				  u16 out_width, u16 out_height,
   2507				  u32 fourcc, bool *five_taps,
   2508				  int *x_predecim, int *y_predecim, u16 pos_x,
   2509				  enum omap_dss_rotation_type rotation_type,
   2510				  bool mem_to_mem)
   2511{
   2512	int maxhdownscale = dispc->feat->max_downscale;
   2513	int maxvdownscale = dispc->feat->max_downscale;
   2514	const int max_decim_limit = 16;
   2515	unsigned long core_clk = 0;
   2516	int decim_x, decim_y, ret;
   2517
   2518	if (width == out_width && height == out_height)
   2519		return 0;
   2520
   2521	if (dispc->feat->supported_scaler_color_modes) {
   2522		const u32 *modes = dispc->feat->supported_scaler_color_modes;
   2523		unsigned int i;
   2524
   2525		for (i = 0; modes[i]; ++i) {
   2526			if (modes[i] == fourcc)
   2527				break;
   2528		}
   2529
   2530		if (modes[i] == 0)
   2531			return -EINVAL;
   2532	}
   2533
   2534	if (plane == OMAP_DSS_WB) {
   2535		switch (fourcc) {
   2536		case DRM_FORMAT_NV12:
   2537			maxhdownscale = maxvdownscale = 2;
   2538			break;
   2539		case DRM_FORMAT_YUYV:
   2540		case DRM_FORMAT_UYVY:
   2541			maxhdownscale = 2;
   2542			maxvdownscale = 4;
   2543			break;
   2544		default:
   2545			break;
   2546		}
   2547	}
   2548	if (!mem_to_mem && (pclk == 0 || vm->pixelclock == 0)) {
   2549		DSSERR("cannot calculate scaling settings: pclk is zero\n");
   2550		return -EINVAL;
   2551	}
   2552
   2553	if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0)
   2554		return -EINVAL;
   2555
   2556	if (mem_to_mem) {
   2557		*x_predecim = *y_predecim = 1;
   2558	} else {
   2559		*x_predecim = max_decim_limit;
   2560		*y_predecim = (rotation_type == OMAP_DSS_ROT_TILER &&
   2561				dispc_has_feature(dispc, FEAT_BURST_2D)) ?
   2562				2 : max_decim_limit;
   2563	}
   2564
   2565	decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxhdownscale);
   2566	decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxvdownscale);
   2567
   2568	if (decim_x > *x_predecim || out_width > width * 8)
   2569		return -EINVAL;
   2570
   2571	if (decim_y > *y_predecim || out_height > height * 8)
   2572		return -EINVAL;
   2573
   2574	ret = dispc->feat->calc_scaling(dispc, pclk, lclk, vm, width, height,
   2575					out_width, out_height, fourcc,
   2576					five_taps, x_predecim, y_predecim,
   2577					&decim_x, &decim_y, pos_x, &core_clk,
   2578					mem_to_mem);
   2579	if (ret)
   2580		return ret;
   2581
   2582	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",
   2583		width, height,
   2584		out_width, out_height,
   2585		out_width / width, DIV_FRAC(out_width, width),
   2586		out_height / height, DIV_FRAC(out_height, height),
   2587
   2588		decim_x, decim_y,
   2589		width / decim_x, height / decim_y,
   2590		out_width / (width / decim_x), DIV_FRAC(out_width, width / decim_x),
   2591		out_height / (height / decim_y), DIV_FRAC(out_height, height / decim_y),
   2592
   2593		*five_taps ? 5 : 3,
   2594		core_clk, dispc_core_clk_rate(dispc));
   2595
   2596	if (!core_clk || core_clk > dispc_core_clk_rate(dispc)) {
   2597		DSSERR("failed to set up scaling, "
   2598			"required core clk rate = %lu Hz, "
   2599			"current core clk rate = %lu Hz\n",
   2600			core_clk, dispc_core_clk_rate(dispc));
   2601		return -EINVAL;
   2602	}
   2603
   2604	*x_predecim = decim_x;
   2605	*y_predecim = decim_y;
   2606	return 0;
   2607}
   2608
   2609void dispc_ovl_get_max_size(struct dispc_device *dispc, u16 *width, u16 *height)
   2610{
   2611	*width = dispc->feat->ovl_width_max;
   2612	*height = dispc->feat->ovl_height_max;
   2613}
   2614
   2615static int dispc_ovl_setup_common(struct dispc_device *dispc,
   2616				  enum omap_plane_id plane,
   2617				  enum omap_overlay_caps caps,
   2618				  u32 paddr, u32 p_uv_addr,
   2619				  u16 screen_width, int pos_x, int pos_y,
   2620				  u16 width, u16 height,
   2621				  u16 out_width, u16 out_height,
   2622				  u32 fourcc, u8 rotation, u8 zorder,
   2623				  u8 pre_mult_alpha, u8 global_alpha,
   2624				  enum omap_dss_rotation_type rotation_type,
   2625				  bool replication, const struct videomode *vm,
   2626				  bool mem_to_mem,
   2627				  enum drm_color_encoding color_encoding,
   2628				  enum drm_color_range color_range)
   2629{
   2630	bool five_taps = true;
   2631	bool fieldmode = false;
   2632	int r, cconv = 0;
   2633	unsigned int offset0, offset1;
   2634	s32 row_inc;
   2635	s32 pix_inc;
   2636	u16 frame_width;
   2637	unsigned int field_offset = 0;
   2638	u16 in_height = height;
   2639	u16 in_width = width;
   2640	int x_predecim = 1, y_predecim = 1;
   2641	bool ilace = !!(vm->flags & DISPLAY_FLAGS_INTERLACED);
   2642	unsigned long pclk = dispc_plane_pclk_rate(dispc, plane);
   2643	unsigned long lclk = dispc_plane_lclk_rate(dispc, plane);
   2644	const struct drm_format_info *info;
   2645
   2646	info = drm_format_info(fourcc);
   2647
   2648	/* when setting up WB, dispc_plane_pclk_rate() returns 0 */
   2649	if (plane == OMAP_DSS_WB)
   2650		pclk = vm->pixelclock;
   2651
   2652	if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER)
   2653		return -EINVAL;
   2654
   2655	if (info->is_yuv && (in_width & 1)) {
   2656		DSSERR("input width %d is not even for YUV format\n", in_width);
   2657		return -EINVAL;
   2658	}
   2659
   2660	out_width = out_width == 0 ? width : out_width;
   2661	out_height = out_height == 0 ? height : out_height;
   2662
   2663	if (plane != OMAP_DSS_WB) {
   2664		if (ilace && height == out_height)
   2665			fieldmode = true;
   2666
   2667		if (ilace) {
   2668			if (fieldmode)
   2669				in_height /= 2;
   2670			pos_y /= 2;
   2671			out_height /= 2;
   2672
   2673			DSSDBG("adjusting for ilace: height %d, pos_y %d, out_height %d\n",
   2674				in_height, pos_y, out_height);
   2675		}
   2676	}
   2677
   2678	if (!dispc_ovl_color_mode_supported(dispc, plane, fourcc))
   2679		return -EINVAL;
   2680
   2681	r = dispc_ovl_calc_scaling(dispc, plane, pclk, lclk, caps, vm, in_width,
   2682				   in_height, out_width, out_height, fourcc,
   2683				   &five_taps, &x_predecim, &y_predecim, pos_x,
   2684				   rotation_type, mem_to_mem);
   2685	if (r)
   2686		return r;
   2687
   2688	in_width = in_width / x_predecim;
   2689	in_height = in_height / y_predecim;
   2690
   2691	if (x_predecim > 1 || y_predecim > 1)
   2692		DSSDBG("predecimation %d x %x, new input size %d x %d\n",
   2693			x_predecim, y_predecim, in_width, in_height);
   2694
   2695	if (info->is_yuv && (in_width & 1)) {
   2696		DSSDBG("predecimated input width is not even for YUV format\n");
   2697		DSSDBG("adjusting input width %d -> %d\n",
   2698			in_width, in_width & ~1);
   2699
   2700		in_width &= ~1;
   2701	}
   2702
   2703	if (info->is_yuv)
   2704		cconv = 1;
   2705
   2706	if (ilace && !fieldmode) {
   2707		/*
   2708		 * when downscaling the bottom field may have to start several
   2709		 * source lines below the top field. Unfortunately ACCUI
   2710		 * registers will only hold the fractional part of the offset
   2711		 * so the integer part must be added to the base address of the
   2712		 * bottom field.
   2713		 */
   2714		if (!in_height || in_height == out_height)
   2715			field_offset = 0;
   2716		else
   2717			field_offset = in_height / out_height / 2;
   2718	}
   2719
   2720	/* Fields are independent but interleaved in memory. */
   2721	if (fieldmode)
   2722		field_offset = 1;
   2723
   2724	offset0 = 0;
   2725	offset1 = 0;
   2726	row_inc = 0;
   2727	pix_inc = 0;
   2728
   2729	if (plane == OMAP_DSS_WB)
   2730		frame_width = out_width;
   2731	else
   2732		frame_width = in_width;
   2733
   2734	calc_offset(screen_width, frame_width,
   2735			fourcc, fieldmode, field_offset,
   2736			&offset0, &offset1, &row_inc, &pix_inc,
   2737			x_predecim, y_predecim,
   2738			rotation_type, rotation);
   2739
   2740	DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
   2741			offset0, offset1, row_inc, pix_inc);
   2742
   2743	dispc_ovl_set_color_mode(dispc, plane, fourcc);
   2744
   2745	dispc_ovl_configure_burst_type(dispc, plane, rotation_type);
   2746
   2747	if (dispc->feat->reverse_ilace_field_order)
   2748		swap(offset0, offset1);
   2749
   2750	dispc_ovl_set_ba0(dispc, plane, paddr + offset0);
   2751	dispc_ovl_set_ba1(dispc, plane, paddr + offset1);
   2752
   2753	if (fourcc == DRM_FORMAT_NV12) {
   2754		dispc_ovl_set_ba0_uv(dispc, plane, p_uv_addr + offset0);
   2755		dispc_ovl_set_ba1_uv(dispc, plane, p_uv_addr + offset1);
   2756	}
   2757
   2758	if (dispc->feat->last_pixel_inc_missing)
   2759		row_inc += pix_inc - 1;
   2760
   2761	dispc_ovl_set_row_inc(dispc, plane, row_inc);
   2762	dispc_ovl_set_pix_inc(dispc, plane, pix_inc);
   2763
   2764	DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width,
   2765			in_height, out_width, out_height);
   2766
   2767	dispc_ovl_set_pos(dispc, plane, caps, pos_x, pos_y);
   2768
   2769	dispc_ovl_set_input_size(dispc, plane, in_width, in_height);
   2770
   2771	if (caps & OMAP_DSS_OVL_CAP_SCALE) {
   2772		dispc_ovl_set_scaling(dispc, plane, in_width, in_height,
   2773				      out_width, out_height, ilace, five_taps,
   2774				      fieldmode, fourcc, rotation);
   2775		dispc_ovl_set_output_size(dispc, plane, out_width, out_height);
   2776		dispc_ovl_set_vid_color_conv(dispc, plane, cconv);
   2777
   2778		if (plane != OMAP_DSS_WB)
   2779			dispc_ovl_set_csc(dispc, plane, color_encoding, color_range);
   2780	}
   2781
   2782	dispc_ovl_set_rotation_attrs(dispc, plane, rotation, rotation_type,
   2783				     fourcc);
   2784
   2785	dispc_ovl_set_zorder(dispc, plane, caps, zorder);
   2786	dispc_ovl_set_pre_mult_alpha(dispc, plane, caps, pre_mult_alpha);
   2787	dispc_ovl_setup_global_alpha(dispc, plane, caps, global_alpha);
   2788
   2789	dispc_ovl_enable_replication(dispc, plane, caps, replication);
   2790
   2791	return 0;
   2792}
   2793
   2794int dispc_ovl_setup(struct dispc_device *dispc,
   2795			   enum omap_plane_id plane,
   2796			   const struct omap_overlay_info *oi,
   2797			   const struct videomode *vm, bool mem_to_mem,
   2798			   enum omap_channel channel)
   2799{
   2800	int r;
   2801	enum omap_overlay_caps caps = dispc->feat->overlay_caps[plane];
   2802	const bool replication = true;
   2803
   2804	DSSDBG("dispc_ovl_setup %d, pa %pad, pa_uv %pad, sw %d, %d,%d, %dx%d ->"
   2805		" %dx%d, cmode %x, rot %d, chan %d repl %d\n",
   2806		plane, &oi->paddr, &oi->p_uv_addr, oi->screen_width, oi->pos_x,
   2807		oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height,
   2808		oi->fourcc, oi->rotation, channel, replication);
   2809
   2810	dispc_ovl_set_channel_out(dispc, plane, channel);
   2811
   2812	r = dispc_ovl_setup_common(dispc, plane, caps, oi->paddr, oi->p_uv_addr,
   2813		oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
   2814		oi->out_width, oi->out_height, oi->fourcc, oi->rotation,
   2815		oi->zorder, oi->pre_mult_alpha, oi->global_alpha,
   2816		oi->rotation_type, replication, vm, mem_to_mem,
   2817		oi->color_encoding, oi->color_range);
   2818
   2819	return r;
   2820}
   2821
   2822int dispc_wb_setup(struct dispc_device *dispc,
   2823		   const struct omap_dss_writeback_info *wi,
   2824		   bool mem_to_mem, const struct videomode *vm,
   2825		   enum dss_writeback_channel channel_in)
   2826{
   2827	int r;
   2828	u32 l;
   2829	enum omap_plane_id plane = OMAP_DSS_WB;
   2830	const int pos_x = 0, pos_y = 0;
   2831	const u8 zorder = 0, global_alpha = 0;
   2832	const bool replication = true;
   2833	bool truncation;
   2834	int in_width = vm->hactive;
   2835	int in_height = vm->vactive;
   2836	enum omap_overlay_caps caps =
   2837		OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA;
   2838
   2839	if (vm->flags & DISPLAY_FLAGS_INTERLACED)
   2840		in_height /= 2;
   2841
   2842	DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, "
   2843		"rot %d\n", wi->paddr, wi->p_uv_addr, in_width,
   2844		in_height, wi->width, wi->height, wi->fourcc, wi->rotation);
   2845
   2846	r = dispc_ovl_setup_common(dispc, plane, caps, wi->paddr, wi->p_uv_addr,
   2847		wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width,
   2848		wi->height, wi->fourcc, wi->rotation, zorder,
   2849		wi->pre_mult_alpha, global_alpha, wi->rotation_type,
   2850		replication, vm, mem_to_mem, DRM_COLOR_YCBCR_BT601,
   2851		DRM_COLOR_YCBCR_LIMITED_RANGE);
   2852	if (r)
   2853		return r;
   2854
   2855	switch (wi->fourcc) {
   2856	case DRM_FORMAT_RGB565:
   2857	case DRM_FORMAT_RGB888:
   2858	case DRM_FORMAT_ARGB4444:
   2859	case DRM_FORMAT_RGBA4444:
   2860	case DRM_FORMAT_RGBX4444:
   2861	case DRM_FORMAT_ARGB1555:
   2862	case DRM_FORMAT_XRGB1555:
   2863	case DRM_FORMAT_XRGB4444:
   2864		truncation = true;
   2865		break;
   2866	default:
   2867		truncation = false;
   2868		break;
   2869	}
   2870
   2871	/* setup extra DISPC_WB_ATTRIBUTES */
   2872	l = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane));
   2873	l = FLD_MOD(l, truncation, 10, 10);	/* TRUNCATIONENABLE */
   2874	l = FLD_MOD(l, channel_in, 18, 16);	/* CHANNELIN */
   2875	l = FLD_MOD(l, mem_to_mem, 19, 19);	/* WRITEBACKMODE */
   2876	if (mem_to_mem)
   2877		l = FLD_MOD(l, 1, 26, 24);	/* CAPTUREMODE */
   2878	else
   2879		l = FLD_MOD(l, 0, 26, 24);	/* CAPTUREMODE */
   2880	dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), l);
   2881
   2882	if (mem_to_mem) {
   2883		/* WBDELAYCOUNT */
   2884		REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), 0, 7, 0);
   2885	} else {
   2886		u32 wbdelay;
   2887
   2888		if (channel_in == DSS_WB_TV_MGR)
   2889			wbdelay = vm->vsync_len + vm->vback_porch;
   2890		else
   2891			wbdelay = vm->vfront_porch + vm->vsync_len +
   2892				vm->vback_porch;
   2893
   2894		if (vm->flags & DISPLAY_FLAGS_INTERLACED)
   2895			wbdelay /= 2;
   2896
   2897		wbdelay = min(wbdelay, 255u);
   2898
   2899		/* WBDELAYCOUNT */
   2900		REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0);
   2901	}
   2902
   2903	return 0;
   2904}
   2905
   2906bool dispc_has_writeback(struct dispc_device *dispc)
   2907{
   2908	return dispc->feat->has_writeback;
   2909}
   2910
   2911int dispc_ovl_enable(struct dispc_device *dispc,
   2912			    enum omap_plane_id plane, bool enable)
   2913{
   2914	DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
   2915
   2916	REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
   2917
   2918	return 0;
   2919}
   2920
   2921static void dispc_lcd_enable_signal_polarity(struct dispc_device *dispc,
   2922					     bool act_high)
   2923{
   2924	if (!dispc_has_feature(dispc, FEAT_LCDENABLEPOL))
   2925		return;
   2926
   2927	REG_FLD_MOD(dispc, DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
   2928}
   2929
   2930void dispc_lcd_enable_signal(struct dispc_device *dispc, bool enable)
   2931{
   2932	if (!dispc_has_feature(dispc, FEAT_LCDENABLESIGNAL))
   2933		return;
   2934
   2935	REG_FLD_MOD(dispc, DISPC_CONTROL, enable ? 1 : 0, 28, 28);
   2936}
   2937
   2938void dispc_pck_free_enable(struct dispc_device *dispc, bool enable)
   2939{
   2940	if (!dispc_has_feature(dispc, FEAT_PCKFREEENABLE))
   2941		return;
   2942
   2943	REG_FLD_MOD(dispc, DISPC_CONTROL, enable ? 1 : 0, 27, 27);
   2944}
   2945
   2946static void dispc_mgr_enable_fifohandcheck(struct dispc_device *dispc,
   2947					   enum omap_channel channel,
   2948					   bool enable)
   2949{
   2950	mgr_fld_write(dispc, channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable);
   2951}
   2952
   2953
   2954static void dispc_mgr_set_lcd_type_tft(struct dispc_device *dispc,
   2955				       enum omap_channel channel)
   2956{
   2957	mgr_fld_write(dispc, channel, DISPC_MGR_FLD_STNTFT, 1);
   2958}
   2959
   2960static void dispc_set_loadmode(struct dispc_device *dispc,
   2961			       enum omap_dss_load_mode mode)
   2962{
   2963	REG_FLD_MOD(dispc, DISPC_CONFIG, mode, 2, 1);
   2964}
   2965
   2966
   2967static void dispc_mgr_set_default_color(struct dispc_device *dispc,
   2968					enum omap_channel channel, u32 color)
   2969{
   2970	dispc_write_reg(dispc, DISPC_DEFAULT_COLOR(channel), color);
   2971}
   2972
   2973static void dispc_mgr_set_trans_key(struct dispc_device *dispc,
   2974				    enum omap_channel ch,
   2975				    enum omap_dss_trans_key_type type,
   2976				    u32 trans_key)
   2977{
   2978	mgr_fld_write(dispc, ch, DISPC_MGR_FLD_TCKSELECTION, type);
   2979
   2980	dispc_write_reg(dispc, DISPC_TRANS_COLOR(ch), trans_key);
   2981}
   2982
   2983static void dispc_mgr_enable_trans_key(struct dispc_device *dispc,
   2984				       enum omap_channel ch, bool enable)
   2985{
   2986	mgr_fld_write(dispc, ch, DISPC_MGR_FLD_TCKENABLE, enable);
   2987}
   2988
   2989static void dispc_mgr_enable_alpha_fixed_zorder(struct dispc_device *dispc,
   2990						enum omap_channel ch,
   2991						bool enable)
   2992{
   2993	if (!dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER))
   2994		return;
   2995
   2996	if (ch == OMAP_DSS_CHANNEL_LCD)
   2997		REG_FLD_MOD(dispc, DISPC_CONFIG, enable, 18, 18);
   2998	else if (ch == OMAP_DSS_CHANNEL_DIGIT)
   2999		REG_FLD_MOD(dispc, DISPC_CONFIG, enable, 19, 19);
   3000}
   3001
   3002void dispc_mgr_setup(struct dispc_device *dispc,
   3003			    enum omap_channel channel,
   3004			    const struct omap_overlay_manager_info *info)
   3005{
   3006	dispc_mgr_set_default_color(dispc, channel, info->default_color);
   3007	dispc_mgr_set_trans_key(dispc, channel, info->trans_key_type,
   3008				info->trans_key);
   3009	dispc_mgr_enable_trans_key(dispc, channel, info->trans_enabled);
   3010	dispc_mgr_enable_alpha_fixed_zorder(dispc, channel,
   3011			info->partial_alpha_enabled);
   3012	if (dispc_has_feature(dispc, FEAT_CPR)) {
   3013		dispc_mgr_enable_cpr(dispc, channel, info->cpr_enable);
   3014		dispc_mgr_set_cpr_coef(dispc, channel, &info->cpr_coefs);
   3015	}
   3016}
   3017
   3018static void dispc_mgr_set_tft_data_lines(struct dispc_device *dispc,
   3019					 enum omap_channel channel,
   3020					 u8 data_lines)
   3021{
   3022	int code;
   3023
   3024	switch (data_lines) {
   3025	case 12:
   3026		code = 0;
   3027		break;
   3028	case 16:
   3029		code = 1;
   3030		break;
   3031	case 18:
   3032		code = 2;
   3033		break;
   3034	case 24:
   3035		code = 3;
   3036		break;
   3037	default:
   3038		BUG();
   3039		return;
   3040	}
   3041
   3042	mgr_fld_write(dispc, channel, DISPC_MGR_FLD_TFTDATALINES, code);
   3043}
   3044
   3045static void dispc_mgr_set_io_pad_mode(struct dispc_device *dispc,
   3046				      enum dss_io_pad_mode mode)
   3047{
   3048	u32 l;
   3049	int gpout0, gpout1;
   3050
   3051	switch (mode) {
   3052	case DSS_IO_PAD_MODE_RESET:
   3053		gpout0 = 0;
   3054		gpout1 = 0;
   3055		break;
   3056	case DSS_IO_PAD_MODE_RFBI:
   3057		gpout0 = 1;
   3058		gpout1 = 0;
   3059		break;
   3060	case DSS_IO_PAD_MODE_BYPASS:
   3061		gpout0 = 1;
   3062		gpout1 = 1;
   3063		break;
   3064	default:
   3065		BUG();
   3066		return;
   3067	}
   3068
   3069	l = dispc_read_reg(dispc, DISPC_CONTROL);
   3070	l = FLD_MOD(l, gpout0, 15, 15);
   3071	l = FLD_MOD(l, gpout1, 16, 16);
   3072	dispc_write_reg(dispc, DISPC_CONTROL, l);
   3073}
   3074
   3075static void dispc_mgr_enable_stallmode(struct dispc_device *dispc,
   3076				       enum omap_channel channel, bool enable)
   3077{
   3078	mgr_fld_write(dispc, channel, DISPC_MGR_FLD_STALLMODE, enable);
   3079}
   3080
   3081void dispc_mgr_set_lcd_config(struct dispc_device *dispc,
   3082				     enum omap_channel channel,
   3083				     const struct dss_lcd_mgr_config *config)
   3084{
   3085	dispc_mgr_set_io_pad_mode(dispc, config->io_pad_mode);
   3086
   3087	dispc_mgr_enable_stallmode(dispc, channel, config->stallmode);
   3088	dispc_mgr_enable_fifohandcheck(dispc, channel, config->fifohandcheck);
   3089
   3090	dispc_mgr_set_clock_div(dispc, channel, &config->clock_info);
   3091
   3092	dispc_mgr_set_tft_data_lines(dispc, channel, config->video_port_width);
   3093
   3094	dispc_lcd_enable_signal_polarity(dispc, config->lcden_sig_polarity);
   3095
   3096	dispc_mgr_set_lcd_type_tft(dispc, channel);
   3097}
   3098
   3099static bool _dispc_mgr_size_ok(struct dispc_device *dispc,
   3100			       u16 width, u16 height)
   3101{
   3102	return width <= dispc->feat->mgr_width_max &&
   3103		height <= dispc->feat->mgr_height_max;
   3104}
   3105
   3106static bool _dispc_lcd_timings_ok(struct dispc_device *dispc,
   3107				  int hsync_len, int hfp, int hbp,
   3108				  int vsw, int vfp, int vbp)
   3109{
   3110	if (hsync_len < 1 || hsync_len > dispc->feat->sw_max ||
   3111	    hfp < 1 || hfp > dispc->feat->hp_max ||
   3112	    hbp < 1 || hbp > dispc->feat->hp_max ||
   3113	    vsw < 1 || vsw > dispc->feat->sw_max ||
   3114	    vfp < 0 || vfp > dispc->feat->vp_max ||
   3115	    vbp < 0 || vbp > dispc->feat->vp_max)
   3116		return false;
   3117	return true;
   3118}
   3119
   3120static bool _dispc_mgr_pclk_ok(struct dispc_device *dispc,
   3121			       enum omap_channel channel,
   3122			       unsigned long pclk)
   3123{
   3124	if (dss_mgr_is_lcd(channel))
   3125		return pclk <= dispc->feat->max_lcd_pclk;
   3126	else
   3127		return pclk <= dispc->feat->max_tv_pclk;
   3128}
   3129
   3130int dispc_mgr_check_timings(struct dispc_device *dispc,
   3131				   enum omap_channel channel,
   3132				   const struct videomode *vm)
   3133{
   3134	if (!_dispc_mgr_size_ok(dispc, vm->hactive, vm->vactive))
   3135		return MODE_BAD;
   3136
   3137	if (!_dispc_mgr_pclk_ok(dispc, channel, vm->pixelclock))
   3138		return MODE_BAD;
   3139
   3140	if (dss_mgr_is_lcd(channel)) {
   3141		/* TODO: OMAP4+ supports interlace for LCD outputs */
   3142		if (vm->flags & DISPLAY_FLAGS_INTERLACED)
   3143			return MODE_BAD;
   3144
   3145		if (!_dispc_lcd_timings_ok(dispc, vm->hsync_len,
   3146				vm->hfront_porch, vm->hback_porch,
   3147				vm->vsync_len, vm->vfront_porch,
   3148				vm->vback_porch))
   3149			return MODE_BAD;
   3150	}
   3151
   3152	return MODE_OK;
   3153}
   3154
   3155static void _dispc_mgr_set_lcd_timings(struct dispc_device *dispc,
   3156				       enum omap_channel channel,
   3157				       const struct videomode *vm)
   3158{
   3159	u32 timing_h, timing_v, l;
   3160	bool onoff, rf, ipc, vs, hs, de;
   3161
   3162	timing_h = FLD_VAL(vm->hsync_len - 1, dispc->feat->sw_start, 0) |
   3163		   FLD_VAL(vm->hfront_porch - 1, dispc->feat->fp_start, 8) |
   3164		   FLD_VAL(vm->hback_porch - 1, dispc->feat->bp_start, 20);
   3165	timing_v = FLD_VAL(vm->vsync_len - 1, dispc->feat->sw_start, 0) |
   3166		   FLD_VAL(vm->vfront_porch, dispc->feat->fp_start, 8) |
   3167		   FLD_VAL(vm->vback_porch, dispc->feat->bp_start, 20);
   3168
   3169	dispc_write_reg(dispc, DISPC_TIMING_H(channel), timing_h);
   3170	dispc_write_reg(dispc, DISPC_TIMING_V(channel), timing_v);
   3171
   3172	vs = !!(vm->flags & DISPLAY_FLAGS_VSYNC_LOW);
   3173	hs = !!(vm->flags & DISPLAY_FLAGS_HSYNC_LOW);
   3174	de = !!(vm->flags & DISPLAY_FLAGS_DE_LOW);
   3175	ipc = !!(vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE);
   3176	onoff = true; /* always use the 'rf' setting */
   3177	rf = !!(vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE);
   3178
   3179	l = FLD_VAL(onoff, 17, 17) |
   3180		FLD_VAL(rf, 16, 16) |
   3181		FLD_VAL(de, 15, 15) |
   3182		FLD_VAL(ipc, 14, 14) |
   3183		FLD_VAL(hs, 13, 13) |
   3184		FLD_VAL(vs, 12, 12);
   3185
   3186	/* always set ALIGN bit when available */
   3187	if (dispc->feat->supports_sync_align)
   3188		l |= (1 << 18);
   3189
   3190	dispc_write_reg(dispc, DISPC_POL_FREQ(channel), l);
   3191
   3192	if (dispc->syscon_pol) {
   3193		const int shifts[] = {
   3194			[OMAP_DSS_CHANNEL_LCD] = 0,
   3195			[OMAP_DSS_CHANNEL_LCD2] = 1,
   3196			[OMAP_DSS_CHANNEL_LCD3] = 2,
   3197		};
   3198
   3199		u32 mask, val;
   3200
   3201		mask = (1 << 0) | (1 << 3) | (1 << 6);
   3202		val = (rf << 0) | (ipc << 3) | (onoff << 6);
   3203
   3204		mask <<= 16 + shifts[channel];
   3205		val <<= 16 + shifts[channel];
   3206
   3207		regmap_update_bits(dispc->syscon_pol, dispc->syscon_pol_offset,
   3208				   mask, val);
   3209	}
   3210}
   3211
   3212static int vm_flag_to_int(enum display_flags flags, enum display_flags high,
   3213	enum display_flags low)
   3214{
   3215	if (flags & high)
   3216		return 1;
   3217	if (flags & low)
   3218		return -1;
   3219	return 0;
   3220}
   3221
   3222/* change name to mode? */
   3223void dispc_mgr_set_timings(struct dispc_device *dispc,
   3224				  enum omap_channel channel,
   3225				  const struct videomode *vm)
   3226{
   3227	unsigned int xtot, ytot;
   3228	unsigned long ht, vt;
   3229	struct videomode t = *vm;
   3230
   3231	DSSDBG("channel %d xres %u yres %u\n", channel, t.hactive, t.vactive);
   3232
   3233	if (dispc_mgr_check_timings(dispc, channel, &t)) {
   3234		BUG();
   3235		return;
   3236	}
   3237
   3238	if (dss_mgr_is_lcd(channel)) {
   3239		_dispc_mgr_set_lcd_timings(dispc, channel, &t);
   3240
   3241		xtot = t.hactive + t.hfront_porch + t.hsync_len + t.hback_porch;
   3242		ytot = t.vactive + t.vfront_porch + t.vsync_len + t.vback_porch;
   3243
   3244		ht = vm->pixelclock / xtot;
   3245		vt = vm->pixelclock / xtot / ytot;
   3246
   3247		DSSDBG("pck %lu\n", vm->pixelclock);
   3248		DSSDBG("hsync_len %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
   3249			t.hsync_len, t.hfront_porch, t.hback_porch,
   3250			t.vsync_len, t.vfront_porch, t.vback_porch);
   3251		DSSDBG("vsync_level %d hsync_level %d data_pclk_edge %d de_level %d sync_pclk_edge %d\n",
   3252			vm_flag_to_int(t.flags, DISPLAY_FLAGS_VSYNC_HIGH, DISPLAY_FLAGS_VSYNC_LOW),
   3253			vm_flag_to_int(t.flags, DISPLAY_FLAGS_HSYNC_HIGH, DISPLAY_FLAGS_HSYNC_LOW),
   3254			vm_flag_to_int(t.flags, DISPLAY_FLAGS_PIXDATA_POSEDGE, DISPLAY_FLAGS_PIXDATA_NEGEDGE),
   3255			vm_flag_to_int(t.flags, DISPLAY_FLAGS_DE_HIGH, DISPLAY_FLAGS_DE_LOW),
   3256			vm_flag_to_int(t.flags, DISPLAY_FLAGS_SYNC_POSEDGE, DISPLAY_FLAGS_SYNC_NEGEDGE));
   3257
   3258		DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
   3259	} else {
   3260		if (t.flags & DISPLAY_FLAGS_INTERLACED)
   3261			t.vactive /= 2;
   3262
   3263		if (dispc->feat->supports_double_pixel)
   3264			REG_FLD_MOD(dispc, DISPC_CONTROL,
   3265				    !!(t.flags & DISPLAY_FLAGS_DOUBLECLK),
   3266				    19, 17);
   3267	}
   3268
   3269	dispc_mgr_set_size(dispc, channel, t.hactive, t.vactive);
   3270}
   3271
   3272static void dispc_mgr_set_lcd_divisor(struct dispc_device *dispc,
   3273				      enum omap_channel channel, u16 lck_div,
   3274				      u16 pck_div)
   3275{
   3276	BUG_ON(lck_div < 1);
   3277	BUG_ON(pck_div < 1);
   3278
   3279	dispc_write_reg(dispc, DISPC_DIVISORo(channel),
   3280			FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
   3281
   3282	if (!dispc_has_feature(dispc, FEAT_CORE_CLK_DIV) &&
   3283			channel == OMAP_DSS_CHANNEL_LCD)
   3284		dispc->core_clk_rate = dispc_fclk_rate(dispc) / lck_div;
   3285}
   3286
   3287static void dispc_mgr_get_lcd_divisor(struct dispc_device *dispc,
   3288				      enum omap_channel channel, int *lck_div,
   3289				      int *pck_div)
   3290{
   3291	u32 l;
   3292	l = dispc_read_reg(dispc, DISPC_DIVISORo(channel));
   3293	*lck_div = FLD_GET(l, 23, 16);
   3294	*pck_div = FLD_GET(l, 7, 0);
   3295}
   3296
   3297static unsigned long dispc_fclk_rate(struct dispc_device *dispc)
   3298{
   3299	unsigned long r;
   3300	enum dss_clk_source src;
   3301
   3302	src = dss_get_dispc_clk_source(dispc->dss);
   3303
   3304	if (src == DSS_CLK_SRC_FCK) {
   3305		r = dss_get_dispc_clk_rate(dispc->dss);
   3306	} else {
   3307		struct dss_pll *pll;
   3308		unsigned int clkout_idx;
   3309
   3310		pll = dss_pll_find_by_src(dispc->dss, src);
   3311		clkout_idx = dss_pll_get_clkout_idx_for_src(src);
   3312
   3313		r = pll->cinfo.clkout[clkout_idx];
   3314	}
   3315
   3316	return r;
   3317}
   3318
   3319static unsigned long dispc_mgr_lclk_rate(struct dispc_device *dispc,
   3320					 enum omap_channel channel)
   3321{
   3322	int lcd;
   3323	unsigned long r;
   3324	enum dss_clk_source src;
   3325
   3326	/* for TV, LCLK rate is the FCLK rate */
   3327	if (!dss_mgr_is_lcd(channel))
   3328		return dispc_fclk_rate(dispc);
   3329
   3330	src = dss_get_lcd_clk_source(dispc->dss, channel);
   3331
   3332	if (src == DSS_CLK_SRC_FCK) {
   3333		r = dss_get_dispc_clk_rate(dispc->dss);
   3334	} else {
   3335		struct dss_pll *pll;
   3336		unsigned int clkout_idx;
   3337
   3338		pll = dss_pll_find_by_src(dispc->dss, src);
   3339		clkout_idx = dss_pll_get_clkout_idx_for_src(src);
   3340
   3341		r = pll->cinfo.clkout[clkout_idx];
   3342	}
   3343
   3344	lcd = REG_GET(dispc, DISPC_DIVISORo(channel), 23, 16);
   3345
   3346	return r / lcd;
   3347}
   3348
   3349static unsigned long dispc_mgr_pclk_rate(struct dispc_device *dispc,
   3350					 enum omap_channel channel)
   3351{
   3352	unsigned long r;
   3353
   3354	if (dss_mgr_is_lcd(channel)) {
   3355		int pcd;
   3356		u32 l;
   3357
   3358		l = dispc_read_reg(dispc, DISPC_DIVISORo(channel));
   3359
   3360		pcd = FLD_GET(l, 7, 0);
   3361
   3362		r = dispc_mgr_lclk_rate(dispc, channel);
   3363
   3364		return r / pcd;
   3365	} else {
   3366		return dispc->tv_pclk_rate;
   3367	}
   3368}
   3369
   3370void dispc_set_tv_pclk(struct dispc_device *dispc, unsigned long pclk)
   3371{
   3372	dispc->tv_pclk_rate = pclk;
   3373}
   3374
   3375static unsigned long dispc_core_clk_rate(struct dispc_device *dispc)
   3376{
   3377	return dispc->core_clk_rate;
   3378}
   3379
   3380static unsigned long dispc_plane_pclk_rate(struct dispc_device *dispc,
   3381					   enum omap_plane_id plane)
   3382{
   3383	enum omap_channel channel;
   3384
   3385	if (plane == OMAP_DSS_WB)
   3386		return 0;
   3387
   3388	channel = dispc_ovl_get_channel_out(dispc, plane);
   3389
   3390	return dispc_mgr_pclk_rate(dispc, channel);
   3391}
   3392
   3393static unsigned long dispc_plane_lclk_rate(struct dispc_device *dispc,
   3394					   enum omap_plane_id plane)
   3395{
   3396	enum omap_channel channel;
   3397
   3398	if (plane == OMAP_DSS_WB)
   3399		return 0;
   3400
   3401	channel	= dispc_ovl_get_channel_out(dispc, plane);
   3402
   3403	return dispc_mgr_lclk_rate(dispc, channel);
   3404}
   3405
   3406static void dispc_dump_clocks_channel(struct dispc_device *dispc,
   3407				      struct seq_file *s,
   3408				      enum omap_channel channel)
   3409{
   3410	int lcd, pcd;
   3411	enum dss_clk_source lcd_clk_src;
   3412
   3413	seq_printf(s, "- %s -\n", mgr_desc[channel].name);
   3414
   3415	lcd_clk_src = dss_get_lcd_clk_source(dispc->dss, channel);
   3416
   3417	seq_printf(s, "%s clk source = %s\n", mgr_desc[channel].name,
   3418		dss_get_clk_source_name(lcd_clk_src));
   3419
   3420	dispc_mgr_get_lcd_divisor(dispc, channel, &lcd, &pcd);
   3421
   3422	seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
   3423		dispc_mgr_lclk_rate(dispc, channel), lcd);
   3424	seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
   3425		dispc_mgr_pclk_rate(dispc, channel), pcd);
   3426}
   3427
   3428void dispc_dump_clocks(struct dispc_device *dispc, struct seq_file *s)
   3429{
   3430	enum dss_clk_source dispc_clk_src;
   3431	int lcd;
   3432	u32 l;
   3433
   3434	if (dispc_runtime_get(dispc))
   3435		return;
   3436
   3437	seq_printf(s, "- DISPC -\n");
   3438
   3439	dispc_clk_src = dss_get_dispc_clk_source(dispc->dss);
   3440	seq_printf(s, "dispc fclk source = %s\n",
   3441			dss_get_clk_source_name(dispc_clk_src));
   3442
   3443	seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate(dispc));
   3444
   3445	if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) {
   3446		seq_printf(s, "- DISPC-CORE-CLK -\n");
   3447		l = dispc_read_reg(dispc, DISPC_DIVISOR);
   3448		lcd = FLD_GET(l, 23, 16);
   3449
   3450		seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
   3451				(dispc_fclk_rate(dispc)/lcd), lcd);
   3452	}
   3453
   3454	dispc_dump_clocks_channel(dispc, s, OMAP_DSS_CHANNEL_LCD);
   3455
   3456	if (dispc_has_feature(dispc, FEAT_MGR_LCD2))
   3457		dispc_dump_clocks_channel(dispc, s, OMAP_DSS_CHANNEL_LCD2);
   3458	if (dispc_has_feature(dispc, FEAT_MGR_LCD3))
   3459		dispc_dump_clocks_channel(dispc, s, OMAP_DSS_CHANNEL_LCD3);
   3460
   3461	dispc_runtime_put(dispc);
   3462}
   3463
   3464static int dispc_dump_regs(struct seq_file *s, void *p)
   3465{
   3466	struct dispc_device *dispc = s->private;
   3467	int i, j;
   3468	const char *mgr_names[] = {
   3469		[OMAP_DSS_CHANNEL_LCD]		= "LCD",
   3470		[OMAP_DSS_CHANNEL_DIGIT]	= "TV",
   3471		[OMAP_DSS_CHANNEL_LCD2]		= "LCD2",
   3472		[OMAP_DSS_CHANNEL_LCD3]		= "LCD3",
   3473	};
   3474	const char *ovl_names[] = {
   3475		[OMAP_DSS_GFX]		= "GFX",
   3476		[OMAP_DSS_VIDEO1]	= "VID1",
   3477		[OMAP_DSS_VIDEO2]	= "VID2",
   3478		[OMAP_DSS_VIDEO3]	= "VID3",
   3479		[OMAP_DSS_WB]		= "WB",
   3480	};
   3481	const char **p_names;
   3482
   3483#define DUMPREG(dispc, r) \
   3484	seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(dispc, r))
   3485
   3486	if (dispc_runtime_get(dispc))
   3487		return 0;
   3488
   3489	/* DISPC common registers */
   3490	DUMPREG(dispc, DISPC_REVISION);
   3491	DUMPREG(dispc, DISPC_SYSCONFIG);
   3492	DUMPREG(dispc, DISPC_SYSSTATUS);
   3493	DUMPREG(dispc, DISPC_IRQSTATUS);
   3494	DUMPREG(dispc, DISPC_IRQENABLE);
   3495	DUMPREG(dispc, DISPC_CONTROL);
   3496	DUMPREG(dispc, DISPC_CONFIG);
   3497	DUMPREG(dispc, DISPC_CAPABLE);
   3498	DUMPREG(dispc, DISPC_LINE_STATUS);
   3499	DUMPREG(dispc, DISPC_LINE_NUMBER);
   3500	if (dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER) ||
   3501			dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER))
   3502		DUMPREG(dispc, DISPC_GLOBAL_ALPHA);
   3503	if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) {
   3504		DUMPREG(dispc, DISPC_CONTROL2);
   3505		DUMPREG(dispc, DISPC_CONFIG2);
   3506	}
   3507	if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) {
   3508		DUMPREG(dispc, DISPC_CONTROL3);
   3509		DUMPREG(dispc, DISPC_CONFIG3);
   3510	}
   3511	if (dispc_has_feature(dispc, FEAT_MFLAG))
   3512		DUMPREG(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE);
   3513
   3514#undef DUMPREG
   3515
   3516#define DISPC_REG(i, name) name(i)
   3517#define DUMPREG(dispc, i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \
   3518	(int)(48 - strlen(#r) - strlen(p_names[i])), " ", \
   3519	dispc_read_reg(dispc, DISPC_REG(i, r)))
   3520
   3521	p_names = mgr_names;
   3522
   3523	/* DISPC channel specific registers */
   3524	for (i = 0; i < dispc_get_num_mgrs(dispc); i++) {
   3525		DUMPREG(dispc, i, DISPC_DEFAULT_COLOR);
   3526		DUMPREG(dispc, i, DISPC_TRANS_COLOR);
   3527		DUMPREG(dispc, i, DISPC_SIZE_MGR);
   3528
   3529		if (i == OMAP_DSS_CHANNEL_DIGIT)
   3530			continue;
   3531
   3532		DUMPREG(dispc, i, DISPC_TIMING_H);
   3533		DUMPREG(dispc, i, DISPC_TIMING_V);
   3534		DUMPREG(dispc, i, DISPC_POL_FREQ);
   3535		DUMPREG(dispc, i, DISPC_DIVISORo);
   3536
   3537		DUMPREG(dispc, i, DISPC_DATA_CYCLE1);
   3538		DUMPREG(dispc, i, DISPC_DATA_CYCLE2);
   3539		DUMPREG(dispc, i, DISPC_DATA_CYCLE3);
   3540
   3541		if (dispc_has_feature(dispc, FEAT_CPR)) {
   3542			DUMPREG(dispc, i, DISPC_CPR_COEF_R);
   3543			DUMPREG(dispc, i, DISPC_CPR_COEF_G);
   3544			DUMPREG(dispc, i, DISPC_CPR_COEF_B);
   3545		}
   3546	}
   3547
   3548	p_names = ovl_names;
   3549
   3550	for (i = 0; i < dispc_get_num_ovls(dispc); i++) {
   3551		DUMPREG(dispc, i, DISPC_OVL_BA0);
   3552		DUMPREG(dispc, i, DISPC_OVL_BA1);
   3553		DUMPREG(dispc, i, DISPC_OVL_POSITION);
   3554		DUMPREG(dispc, i, DISPC_OVL_SIZE);
   3555		DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES);
   3556		DUMPREG(dispc, i, DISPC_OVL_FIFO_THRESHOLD);
   3557		DUMPREG(dispc, i, DISPC_OVL_FIFO_SIZE_STATUS);
   3558		DUMPREG(dispc, i, DISPC_OVL_ROW_INC);
   3559		DUMPREG(dispc, i, DISPC_OVL_PIXEL_INC);
   3560
   3561		if (dispc_has_feature(dispc, FEAT_PRELOAD))
   3562			DUMPREG(dispc, i, DISPC_OVL_PRELOAD);
   3563		if (dispc_has_feature(dispc, FEAT_MFLAG))
   3564			DUMPREG(dispc, i, DISPC_OVL_MFLAG_THRESHOLD);
   3565
   3566		if (i == OMAP_DSS_GFX) {
   3567			DUMPREG(dispc, i, DISPC_OVL_WINDOW_SKIP);
   3568			DUMPREG(dispc, i, DISPC_OVL_TABLE_BA);
   3569			continue;
   3570		}
   3571
   3572		DUMPREG(dispc, i, DISPC_OVL_FIR);
   3573		DUMPREG(dispc, i, DISPC_OVL_PICTURE_SIZE);
   3574		DUMPREG(dispc, i, DISPC_OVL_ACCU0);
   3575		DUMPREG(dispc, i, DISPC_OVL_ACCU1);
   3576		if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) {
   3577			DUMPREG(dispc, i, DISPC_OVL_BA0_UV);
   3578			DUMPREG(dispc, i, DISPC_OVL_BA1_UV);
   3579			DUMPREG(dispc, i, DISPC_OVL_FIR2);
   3580			DUMPREG(dispc, i, DISPC_OVL_ACCU2_0);
   3581			DUMPREG(dispc, i, DISPC_OVL_ACCU2_1);
   3582		}
   3583		if (dispc_has_feature(dispc, FEAT_ATTR2))
   3584			DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES2);
   3585	}
   3586
   3587	if (dispc->feat->has_writeback) {
   3588		i = OMAP_DSS_WB;
   3589		DUMPREG(dispc, i, DISPC_OVL_BA0);
   3590		DUMPREG(dispc, i, DISPC_OVL_BA1);
   3591		DUMPREG(dispc, i, DISPC_OVL_SIZE);
   3592		DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES);
   3593		DUMPREG(dispc, i, DISPC_OVL_FIFO_THRESHOLD);
   3594		DUMPREG(dispc, i, DISPC_OVL_FIFO_SIZE_STATUS);
   3595		DUMPREG(dispc, i, DISPC_OVL_ROW_INC);
   3596		DUMPREG(dispc, i, DISPC_OVL_PIXEL_INC);
   3597
   3598		if (dispc_has_feature(dispc, FEAT_MFLAG))
   3599			DUMPREG(dispc, i, DISPC_OVL_MFLAG_THRESHOLD);
   3600
   3601		DUMPREG(dispc, i, DISPC_OVL_FIR);
   3602		DUMPREG(dispc, i, DISPC_OVL_PICTURE_SIZE);
   3603		DUMPREG(dispc, i, DISPC_OVL_ACCU0);
   3604		DUMPREG(dispc, i, DISPC_OVL_ACCU1);
   3605		if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) {
   3606			DUMPREG(dispc, i, DISPC_OVL_BA0_UV);
   3607			DUMPREG(dispc, i, DISPC_OVL_BA1_UV);
   3608			DUMPREG(dispc, i, DISPC_OVL_FIR2);
   3609			DUMPREG(dispc, i, DISPC_OVL_ACCU2_0);
   3610			DUMPREG(dispc, i, DISPC_OVL_ACCU2_1);
   3611		}
   3612		if (dispc_has_feature(dispc, FEAT_ATTR2))
   3613			DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES2);
   3614	}
   3615
   3616#undef DISPC_REG
   3617#undef DUMPREG
   3618
   3619#define DISPC_REG(plane, name, i) name(plane, i)
   3620#define DUMPREG(dispc, plane, name, i) \
   3621	seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \
   3622	(int)(46 - strlen(#name) - strlen(p_names[plane])), " ", \
   3623	dispc_read_reg(dispc, DISPC_REG(plane, name, i)))
   3624
   3625	/* Video pipeline coefficient registers */
   3626
   3627	/* start from OMAP_DSS_VIDEO1 */
   3628	for (i = 1; i < dispc_get_num_ovls(dispc); i++) {
   3629		for (j = 0; j < 8; j++)
   3630			DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_H, j);
   3631
   3632		for (j = 0; j < 8; j++)
   3633			DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_HV, j);
   3634
   3635		for (j = 0; j < 5; j++)
   3636			DUMPREG(dispc, i, DISPC_OVL_CONV_COEF, j);
   3637
   3638		if (dispc_has_feature(dispc, FEAT_FIR_COEF_V)) {
   3639			for (j = 0; j < 8; j++)
   3640				DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_V, j);
   3641		}
   3642
   3643		if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) {
   3644			for (j = 0; j < 8; j++)
   3645				DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_H2, j);
   3646
   3647			for (j = 0; j < 8; j++)
   3648				DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_HV2, j);
   3649
   3650			for (j = 0; j < 8; j++)
   3651				DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_V2, j);
   3652		}
   3653	}
   3654
   3655	dispc_runtime_put(dispc);
   3656
   3657#undef DISPC_REG
   3658#undef DUMPREG
   3659
   3660	return 0;
   3661}
   3662
   3663/* calculate clock rates using dividers in cinfo */
   3664int dispc_calc_clock_rates(struct dispc_device *dispc,
   3665			   unsigned long dispc_fclk_rate,
   3666			   struct dispc_clock_info *cinfo)
   3667{
   3668	if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
   3669		return -EINVAL;
   3670	if (cinfo->pck_div < 1 || cinfo->pck_div > 255)
   3671		return -EINVAL;
   3672
   3673	cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
   3674	cinfo->pck = cinfo->lck / cinfo->pck_div;
   3675
   3676	return 0;
   3677}
   3678
   3679bool dispc_div_calc(struct dispc_device *dispc, unsigned long dispc_freq,
   3680		    unsigned long pck_min, unsigned long pck_max,
   3681		    dispc_div_calc_func func, void *data)
   3682{
   3683	int lckd, lckd_start, lckd_stop;
   3684	int pckd, pckd_start, pckd_stop;
   3685	unsigned long pck, lck;
   3686	unsigned long lck_max;
   3687	unsigned long pckd_hw_min, pckd_hw_max;
   3688	unsigned int min_fck_per_pck;
   3689	unsigned long fck;
   3690
   3691#ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK
   3692	min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
   3693#else
   3694	min_fck_per_pck = 0;
   3695#endif
   3696
   3697	pckd_hw_min = dispc->feat->min_pcd;
   3698	pckd_hw_max = 255;
   3699
   3700	lck_max = dss_get_max_fck_rate(dispc->dss);
   3701
   3702	pck_min = pck_min ? pck_min : 1;
   3703	pck_max = pck_max ? pck_max : ULONG_MAX;
   3704
   3705	lckd_start = max(DIV_ROUND_UP(dispc_freq, lck_max), 1ul);
   3706	lckd_stop = min(dispc_freq / pck_min, 255ul);
   3707
   3708	for (lckd = lckd_start; lckd <= lckd_stop; ++lckd) {
   3709		lck = dispc_freq / lckd;
   3710
   3711		pckd_start = max(DIV_ROUND_UP(lck, pck_max), pckd_hw_min);
   3712		pckd_stop = min(lck / pck_min, pckd_hw_max);
   3713
   3714		for (pckd = pckd_start; pckd <= pckd_stop; ++pckd) {
   3715			pck = lck / pckd;
   3716
   3717			/*
   3718			 * For OMAP2/3 the DISPC fclk is the same as LCD's logic
   3719			 * clock, which means we're configuring DISPC fclk here
   3720			 * also. Thus we need to use the calculated lck. For
   3721			 * OMAP4+ the DISPC fclk is a separate clock.
   3722			 */
   3723			if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV))
   3724				fck = dispc_core_clk_rate(dispc);
   3725			else
   3726				fck = lck;
   3727
   3728			if (fck < pck * min_fck_per_pck)
   3729				continue;
   3730
   3731			if (func(lckd, pckd, lck, pck, data))
   3732				return true;
   3733		}
   3734	}
   3735
   3736	return false;
   3737}
   3738
   3739void dispc_mgr_set_clock_div(struct dispc_device *dispc,
   3740			     enum omap_channel channel,
   3741			     const struct dispc_clock_info *cinfo)
   3742{
   3743	DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
   3744	DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
   3745
   3746	dispc_mgr_set_lcd_divisor(dispc, channel, cinfo->lck_div,
   3747				  cinfo->pck_div);
   3748}
   3749
   3750int dispc_mgr_get_clock_div(struct dispc_device *dispc,
   3751			    enum omap_channel channel,
   3752			    struct dispc_clock_info *cinfo)
   3753{
   3754	unsigned long fck;
   3755
   3756	fck = dispc_fclk_rate(dispc);
   3757
   3758	cinfo->lck_div = REG_GET(dispc, DISPC_DIVISORo(channel), 23, 16);
   3759	cinfo->pck_div = REG_GET(dispc, DISPC_DIVISORo(channel), 7, 0);
   3760
   3761	cinfo->lck = fck / cinfo->lck_div;
   3762	cinfo->pck = cinfo->lck / cinfo->pck_div;
   3763
   3764	return 0;
   3765}
   3766
   3767u32 dispc_read_irqstatus(struct dispc_device *dispc)
   3768{
   3769	return dispc_read_reg(dispc, DISPC_IRQSTATUS);
   3770}
   3771
   3772void dispc_clear_irqstatus(struct dispc_device *dispc, u32 mask)
   3773{
   3774	dispc_write_reg(dispc, DISPC_IRQSTATUS, mask);
   3775}
   3776
   3777void dispc_write_irqenable(struct dispc_device *dispc, u32 mask)
   3778{
   3779	u32 old_mask = dispc_read_reg(dispc, DISPC_IRQENABLE);
   3780
   3781	/* clear the irqstatus for newly enabled irqs */
   3782	dispc_clear_irqstatus(dispc, (mask ^ old_mask) & mask);
   3783
   3784	dispc_write_reg(dispc, DISPC_IRQENABLE, mask);
   3785
   3786	/* flush posted write */
   3787	dispc_read_reg(dispc, DISPC_IRQENABLE);
   3788}
   3789
   3790void dispc_enable_sidle(struct dispc_device *dispc)
   3791{
   3792	/* SIDLEMODE: smart idle */
   3793	REG_FLD_MOD(dispc, DISPC_SYSCONFIG, 2, 4, 3);
   3794}
   3795
   3796void dispc_disable_sidle(struct dispc_device *dispc)
   3797{
   3798	REG_FLD_MOD(dispc, DISPC_SYSCONFIG, 1, 4, 3);	/* SIDLEMODE: no idle */
   3799}
   3800
   3801u32 dispc_mgr_gamma_size(struct dispc_device *dispc,
   3802				enum omap_channel channel)
   3803{
   3804	const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
   3805
   3806	if (!dispc->feat->has_gamma_table)
   3807		return 0;
   3808
   3809	return gdesc->len;
   3810}
   3811
   3812static void dispc_mgr_write_gamma_table(struct dispc_device *dispc,
   3813					enum omap_channel channel)
   3814{
   3815	const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
   3816	u32 *table = dispc->gamma_table[channel];
   3817	unsigned int i;
   3818
   3819	DSSDBG("%s: channel %d\n", __func__, channel);
   3820
   3821	for (i = 0; i < gdesc->len; ++i) {
   3822		u32 v = table[i];
   3823
   3824		if (gdesc->has_index)
   3825			v |= i << 24;
   3826		else if (i == 0)
   3827			v |= 1 << 31;
   3828
   3829		dispc_write_reg(dispc, gdesc->reg, v);
   3830	}
   3831}
   3832
   3833static void dispc_restore_gamma_tables(struct dispc_device *dispc)
   3834{
   3835	DSSDBG("%s()\n", __func__);
   3836
   3837	if (!dispc->feat->has_gamma_table)
   3838		return;
   3839
   3840	dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_LCD);
   3841
   3842	dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_DIGIT);
   3843
   3844	if (dispc_has_feature(dispc, FEAT_MGR_LCD2))
   3845		dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_LCD2);
   3846
   3847	if (dispc_has_feature(dispc, FEAT_MGR_LCD3))
   3848		dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_LCD3);
   3849}
   3850
   3851static const struct drm_color_lut dispc_mgr_gamma_default_lut[] = {
   3852	{ .red = 0, .green = 0, .blue = 0, },
   3853	{ .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, },
   3854};
   3855
   3856void dispc_mgr_set_gamma(struct dispc_device *dispc,
   3857				enum omap_channel channel,
   3858				const struct drm_color_lut *lut,
   3859				unsigned int length)
   3860{
   3861	const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
   3862	u32 *table = dispc->gamma_table[channel];
   3863	uint i;
   3864
   3865	DSSDBG("%s: channel %d, lut len %u, hw len %u\n", __func__,
   3866	       channel, length, gdesc->len);
   3867
   3868	if (!dispc->feat->has_gamma_table)
   3869		return;
   3870
   3871	if (lut == NULL || length < 2) {
   3872		lut = dispc_mgr_gamma_default_lut;
   3873		length = ARRAY_SIZE(dispc_mgr_gamma_default_lut);
   3874	}
   3875
   3876	for (i = 0; i < length - 1; ++i) {
   3877		uint first = i * (gdesc->len - 1) / (length - 1);
   3878		uint last = (i + 1) * (gdesc->len - 1) / (length - 1);
   3879		uint w = last - first;
   3880		u16 r, g, b;
   3881		uint j;
   3882
   3883		if (w == 0)
   3884			continue;
   3885
   3886		for (j = 0; j <= w; j++) {
   3887			r = (lut[i].red * (w - j) + lut[i+1].red * j) / w;
   3888			g = (lut[i].green * (w - j) + lut[i+1].green * j) / w;
   3889			b = (lut[i].blue * (w - j) + lut[i+1].blue * j) / w;
   3890
   3891			r >>= 16 - gdesc->bits;
   3892			g >>= 16 - gdesc->bits;
   3893			b >>= 16 - gdesc->bits;
   3894
   3895			table[first + j] = (r << (gdesc->bits * 2)) |
   3896				(g << gdesc->bits) | b;
   3897		}
   3898	}
   3899
   3900	if (dispc->is_enabled)
   3901		dispc_mgr_write_gamma_table(dispc, channel);
   3902}
   3903
   3904static int dispc_init_gamma_tables(struct dispc_device *dispc)
   3905{
   3906	int channel;
   3907
   3908	if (!dispc->feat->has_gamma_table)
   3909		return 0;
   3910
   3911	for (channel = 0; channel < ARRAY_SIZE(dispc->gamma_table); channel++) {
   3912		const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
   3913		u32 *gt;
   3914
   3915		if (channel == OMAP_DSS_CHANNEL_LCD2 &&
   3916		    !dispc_has_feature(dispc, FEAT_MGR_LCD2))
   3917			continue;
   3918
   3919		if (channel == OMAP_DSS_CHANNEL_LCD3 &&
   3920		    !dispc_has_feature(dispc, FEAT_MGR_LCD3))
   3921			continue;
   3922
   3923		gt = devm_kmalloc_array(&dispc->pdev->dev, gdesc->len,
   3924					sizeof(u32), GFP_KERNEL);
   3925		if (!gt)
   3926			return -ENOMEM;
   3927
   3928		dispc->gamma_table[channel] = gt;
   3929
   3930		dispc_mgr_set_gamma(dispc, channel, NULL, 0);
   3931	}
   3932	return 0;
   3933}
   3934
   3935static void _omap_dispc_initial_config(struct dispc_device *dispc)
   3936{
   3937	u32 l;
   3938
   3939	/* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
   3940	if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) {
   3941		l = dispc_read_reg(dispc, DISPC_DIVISOR);
   3942		/* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
   3943		l = FLD_MOD(l, 1, 0, 0);
   3944		l = FLD_MOD(l, 1, 23, 16);
   3945		dispc_write_reg(dispc, DISPC_DIVISOR, l);
   3946
   3947		dispc->core_clk_rate = dispc_fclk_rate(dispc);
   3948	}
   3949
   3950	/* Use gamma table mode, instead of palette mode */
   3951	if (dispc->feat->has_gamma_table)
   3952		REG_FLD_MOD(dispc, DISPC_CONFIG, 1, 3, 3);
   3953
   3954	/* For older DSS versions (FEAT_FUNCGATED) this enables
   3955	 * func-clock auto-gating. For newer versions
   3956	 * (dispc->feat->has_gamma_table) this enables tv-out gamma tables.
   3957	 */
   3958	if (dispc_has_feature(dispc, FEAT_FUNCGATED) ||
   3959	    dispc->feat->has_gamma_table)
   3960		REG_FLD_MOD(dispc, DISPC_CONFIG, 1, 9, 9);
   3961
   3962	dispc_set_loadmode(dispc, OMAP_DSS_LOAD_FRAME_ONLY);
   3963
   3964	dispc_init_fifos(dispc);
   3965
   3966	dispc_configure_burst_sizes(dispc);
   3967
   3968	dispc_ovl_enable_zorder_planes(dispc);
   3969
   3970	if (dispc->feat->mstandby_workaround)
   3971		REG_FLD_MOD(dispc, DISPC_MSTANDBY_CTRL, 1, 0, 0);
   3972
   3973	if (dispc_has_feature(dispc, FEAT_MFLAG))
   3974		dispc_init_mflag(dispc);
   3975}
   3976
   3977static const enum dispc_feature_id omap2_dispc_features_list[] = {
   3978	FEAT_LCDENABLEPOL,
   3979	FEAT_LCDENABLESIGNAL,
   3980	FEAT_PCKFREEENABLE,
   3981	FEAT_FUNCGATED,
   3982	FEAT_ROWREPEATENABLE,
   3983	FEAT_RESIZECONF,
   3984};
   3985
   3986static const enum dispc_feature_id omap3_dispc_features_list[] = {
   3987	FEAT_LCDENABLEPOL,
   3988	FEAT_LCDENABLESIGNAL,
   3989	FEAT_PCKFREEENABLE,
   3990	FEAT_FUNCGATED,
   3991	FEAT_LINEBUFFERSPLIT,
   3992	FEAT_ROWREPEATENABLE,
   3993	FEAT_RESIZECONF,
   3994	FEAT_CPR,
   3995	FEAT_PRELOAD,
   3996	FEAT_FIR_COEF_V,
   3997	FEAT_ALPHA_FIXED_ZORDER,
   3998	FEAT_FIFO_MERGE,
   3999	FEAT_OMAP3_DSI_FIFO_BUG,
   4000};
   4001
   4002static const enum dispc_feature_id am43xx_dispc_features_list[] = {
   4003	FEAT_LCDENABLEPOL,
   4004	FEAT_LCDENABLESIGNAL,
   4005	FEAT_PCKFREEENABLE,
   4006	FEAT_FUNCGATED,
   4007	FEAT_LINEBUFFERSPLIT,
   4008	FEAT_ROWREPEATENABLE,
   4009	FEAT_RESIZECONF,
   4010	FEAT_CPR,
   4011	FEAT_PRELOAD,
   4012	FEAT_FIR_COEF_V,
   4013	FEAT_ALPHA_FIXED_ZORDER,
   4014	FEAT_FIFO_MERGE,
   4015};
   4016
   4017static const enum dispc_feature_id omap4_dispc_features_list[] = {
   4018	FEAT_MGR_LCD2,
   4019	FEAT_CORE_CLK_DIV,
   4020	FEAT_HANDLE_UV_SEPARATE,
   4021	FEAT_ATTR2,
   4022	FEAT_CPR,
   4023	FEAT_PRELOAD,
   4024	FEAT_FIR_COEF_V,
   4025	FEAT_ALPHA_FREE_ZORDER,
   4026	FEAT_FIFO_MERGE,
   4027	FEAT_BURST_2D,
   4028};
   4029
   4030static const enum dispc_feature_id omap5_dispc_features_list[] = {
   4031	FEAT_MGR_LCD2,
   4032	FEAT_MGR_LCD3,
   4033	FEAT_CORE_CLK_DIV,
   4034	FEAT_HANDLE_UV_SEPARATE,
   4035	FEAT_ATTR2,
   4036	FEAT_CPR,
   4037	FEAT_PRELOAD,
   4038	FEAT_FIR_COEF_V,
   4039	FEAT_ALPHA_FREE_ZORDER,
   4040	FEAT_FIFO_MERGE,
   4041	FEAT_BURST_2D,
   4042	FEAT_MFLAG,
   4043};
   4044
   4045static const struct dss_reg_field omap2_dispc_reg_fields[] = {
   4046	[FEAT_REG_FIRHINC]			= { 11, 0 },
   4047	[FEAT_REG_FIRVINC]			= { 27, 16 },
   4048	[FEAT_REG_FIFOLOWTHRESHOLD]		= { 8, 0 },
   4049	[FEAT_REG_FIFOHIGHTHRESHOLD]		= { 24, 16 },
   4050	[FEAT_REG_FIFOSIZE]			= { 8, 0 },
   4051	[FEAT_REG_HORIZONTALACCU]		= { 9, 0 },
   4052	[FEAT_REG_VERTICALACCU]			= { 25, 16 },
   4053};
   4054
   4055static const struct dss_reg_field omap3_dispc_reg_fields[] = {
   4056	[FEAT_REG_FIRHINC]			= { 12, 0 },
   4057	[FEAT_REG_FIRVINC]			= { 28, 16 },
   4058	[FEAT_REG_FIFOLOWTHRESHOLD]		= { 11, 0 },
   4059	[FEAT_REG_FIFOHIGHTHRESHOLD]		= { 27, 16 },
   4060	[FEAT_REG_FIFOSIZE]			= { 10, 0 },
   4061	[FEAT_REG_HORIZONTALACCU]		= { 9, 0 },
   4062	[FEAT_REG_VERTICALACCU]			= { 25, 16 },
   4063};
   4064
   4065static const struct dss_reg_field omap4_dispc_reg_fields[] = {
   4066	[FEAT_REG_FIRHINC]			= { 12, 0 },
   4067	[FEAT_REG_FIRVINC]			= { 28, 16 },
   4068	[FEAT_REG_FIFOLOWTHRESHOLD]		= { 15, 0 },
   4069	[FEAT_REG_FIFOHIGHTHRESHOLD]		= { 31, 16 },
   4070	[FEAT_REG_FIFOSIZE]			= { 15, 0 },
   4071	[FEAT_REG_HORIZONTALACCU]		= { 10, 0 },
   4072	[FEAT_REG_VERTICALACCU]			= { 26, 16 },
   4073};
   4074
   4075static const enum omap_overlay_caps omap2_dispc_overlay_caps[] = {
   4076	/* OMAP_DSS_GFX */
   4077	OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
   4078
   4079	/* OMAP_DSS_VIDEO1 */
   4080	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
   4081		OMAP_DSS_OVL_CAP_REPLICATION,
   4082
   4083	/* OMAP_DSS_VIDEO2 */
   4084	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
   4085		OMAP_DSS_OVL_CAP_REPLICATION,
   4086};
   4087
   4088static const enum omap_overlay_caps omap3430_dispc_overlay_caps[] = {
   4089	/* OMAP_DSS_GFX */
   4090	OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_POS |
   4091		OMAP_DSS_OVL_CAP_REPLICATION,
   4092
   4093	/* OMAP_DSS_VIDEO1 */
   4094	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
   4095		OMAP_DSS_OVL_CAP_REPLICATION,
   4096
   4097	/* OMAP_DSS_VIDEO2 */
   4098	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
   4099		OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
   4100};
   4101
   4102static const enum omap_overlay_caps omap3630_dispc_overlay_caps[] = {
   4103	/* OMAP_DSS_GFX */
   4104	OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
   4105		OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
   4106
   4107	/* OMAP_DSS_VIDEO1 */
   4108	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
   4109		OMAP_DSS_OVL_CAP_REPLICATION,
   4110
   4111	/* OMAP_DSS_VIDEO2 */
   4112	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
   4113		OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_POS |
   4114		OMAP_DSS_OVL_CAP_REPLICATION,
   4115};
   4116
   4117static const enum omap_overlay_caps omap4_dispc_overlay_caps[] = {
   4118	/* OMAP_DSS_GFX */
   4119	OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
   4120		OMAP_DSS_OVL_CAP_ZORDER | OMAP_DSS_OVL_CAP_POS |
   4121		OMAP_DSS_OVL_CAP_REPLICATION,
   4122
   4123	/* OMAP_DSS_VIDEO1 */
   4124	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
   4125		OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
   4126		OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
   4127
   4128	/* OMAP_DSS_VIDEO2 */
   4129	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
   4130		OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
   4131		OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
   4132
   4133	/* OMAP_DSS_VIDEO3 */
   4134	OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
   4135		OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
   4136		OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
   4137};
   4138
   4139#define COLOR_ARRAY(arr...) (const u32[]) { arr, 0 }
   4140
   4141static const u32 *omap2_dispc_supported_color_modes[] = {
   4142
   4143	/* OMAP_DSS_GFX */
   4144	COLOR_ARRAY(
   4145	DRM_FORMAT_RGBX4444, DRM_FORMAT_RGB565,
   4146	DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB888),
   4147
   4148	/* OMAP_DSS_VIDEO1 */
   4149	COLOR_ARRAY(
   4150	DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888,
   4151	DRM_FORMAT_RGB888, DRM_FORMAT_YUYV,
   4152	DRM_FORMAT_UYVY),
   4153
   4154	/* OMAP_DSS_VIDEO2 */
   4155	COLOR_ARRAY(
   4156	DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888,
   4157	DRM_FORMAT_RGB888, DRM_FORMAT_YUYV,
   4158	DRM_FORMAT_UYVY),
   4159};
   4160
   4161static const u32 *omap3_dispc_supported_color_modes[] = {
   4162	/* OMAP_DSS_GFX */
   4163	COLOR_ARRAY(
   4164	DRM_FORMAT_RGBX4444, DRM_FORMAT_ARGB4444,
   4165	DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888,
   4166	DRM_FORMAT_RGB888, DRM_FORMAT_ARGB8888,
   4167	DRM_FORMAT_RGBA8888, DRM_FORMAT_RGBX8888),
   4168
   4169	/* OMAP_DSS_VIDEO1 */
   4170	COLOR_ARRAY(
   4171	DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB888,
   4172	DRM_FORMAT_RGBX4444, DRM_FORMAT_RGB565,
   4173	DRM_FORMAT_YUYV, DRM_FORMAT_UYVY),
   4174
   4175	/* OMAP_DSS_VIDEO2 */
   4176	COLOR_ARRAY(
   4177	DRM_FORMAT_RGBX4444, DRM_FORMAT_ARGB4444,
   4178	DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888,
   4179	DRM_FORMAT_RGB888, DRM_FORMAT_YUYV,
   4180	DRM_FORMAT_UYVY, DRM_FORMAT_ARGB8888,
   4181	DRM_FORMAT_RGBA8888, DRM_FORMAT_RGBX8888),
   4182};
   4183
   4184static const u32 *omap4_dispc_supported_color_modes[] = {
   4185	/* OMAP_DSS_GFX */
   4186	COLOR_ARRAY(
   4187	DRM_FORMAT_RGBX4444, DRM_FORMAT_ARGB4444,
   4188	DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888,
   4189	DRM_FORMAT_RGB888, DRM_FORMAT_ARGB8888,
   4190	DRM_FORMAT_RGBA8888, DRM_FORMAT_RGBX8888,
   4191	DRM_FORMAT_ARGB1555, DRM_FORMAT_XRGB4444,
   4192	DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB1555),
   4193
   4194	/* OMAP_DSS_VIDEO1 */
   4195	COLOR_ARRAY(
   4196	DRM_FORMAT_RGB565, DRM_FORMAT_RGBX4444,
   4197	DRM_FORMAT_YUYV, DRM_FORMAT_ARGB1555,
   4198	DRM_FORMAT_RGBA8888, DRM_FORMAT_NV12,
   4199	DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB8888,
   4200	DRM_FORMAT_RGB888, DRM_FORMAT_UYVY,
   4201	DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555,
   4202	DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB4444,
   4203	DRM_FORMAT_RGBX8888),
   4204
   4205       /* OMAP_DSS_VIDEO2 */
   4206	COLOR_ARRAY(
   4207	DRM_FORMAT_RGB565, DRM_FORMAT_RGBX4444,
   4208	DRM_FORMAT_YUYV, DRM_FORMAT_ARGB1555,
   4209	DRM_FORMAT_RGBA8888, DRM_FORMAT_NV12,
   4210	DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB8888,
   4211	DRM_FORMAT_RGB888, DRM_FORMAT_UYVY,
   4212	DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555,
   4213	DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB4444,
   4214	DRM_FORMAT_RGBX8888),
   4215
   4216	/* OMAP_DSS_VIDEO3 */
   4217	COLOR_ARRAY(
   4218	DRM_FORMAT_RGB565, DRM_FORMAT_RGBX4444,
   4219	DRM_FORMAT_YUYV, DRM_FORMAT_ARGB1555,
   4220	DRM_FORMAT_RGBA8888, DRM_FORMAT_NV12,
   4221	DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB8888,
   4222	DRM_FORMAT_RGB888, DRM_FORMAT_UYVY,
   4223	DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555,
   4224	DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB4444,
   4225	DRM_FORMAT_RGBX8888),
   4226
   4227	/* OMAP_DSS_WB */
   4228	COLOR_ARRAY(
   4229	DRM_FORMAT_RGB565, DRM_FORMAT_RGBX4444,
   4230	DRM_FORMAT_YUYV, DRM_FORMAT_ARGB1555,
   4231	DRM_FORMAT_RGBA8888, DRM_FORMAT_NV12,
   4232	DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB8888,
   4233	DRM_FORMAT_RGB888, DRM_FORMAT_UYVY,
   4234	DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555,
   4235	DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB4444,
   4236	DRM_FORMAT_RGBX8888),
   4237};
   4238
   4239static const u32 omap3_dispc_supported_scaler_color_modes[] = {
   4240	DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB565, DRM_FORMAT_YUYV,
   4241	DRM_FORMAT_UYVY,
   4242	0,
   4243};
   4244
   4245static const struct dispc_features omap24xx_dispc_feats = {
   4246	.sw_start		=	5,
   4247	.fp_start		=	15,
   4248	.bp_start		=	27,
   4249	.sw_max			=	64,
   4250	.vp_max			=	255,
   4251	.hp_max			=	256,
   4252	.mgr_width_start	=	10,
   4253	.mgr_height_start	=	26,
   4254	.mgr_width_max		=	2048,
   4255	.mgr_height_max		=	2048,
   4256	.ovl_width_max		=	2048,
   4257	.ovl_height_max		=	2048,
   4258	.max_lcd_pclk		=	66500000,
   4259	.max_downscale		=	2,
   4260	/*
   4261	 * Assume the line width buffer to be 768 pixels as OMAP2 DISPC scaler
   4262	 * cannot scale an image width larger than 768.
   4263	 */
   4264	.max_line_width		=	768,
   4265	.min_pcd		=	2,
   4266	.calc_scaling		=	dispc_ovl_calc_scaling_24xx,
   4267	.calc_core_clk		=	calc_core_clk_24xx,
   4268	.num_fifos		=	3,
   4269	.features		=	omap2_dispc_features_list,
   4270	.num_features		=	ARRAY_SIZE(omap2_dispc_features_list),
   4271	.reg_fields		=	omap2_dispc_reg_fields,
   4272	.num_reg_fields		=	ARRAY_SIZE(omap2_dispc_reg_fields),
   4273	.overlay_caps		=	omap2_dispc_overlay_caps,
   4274	.supported_color_modes	=	omap2_dispc_supported_color_modes,
   4275	.supported_scaler_color_modes = COLOR_ARRAY(DRM_FORMAT_XRGB8888),
   4276	.num_mgrs		=	2,
   4277	.num_ovls		=	3,
   4278	.buffer_size_unit	=	1,
   4279	.burst_size_unit	=	8,
   4280	.no_framedone_tv	=	true,
   4281	.set_max_preload	=	false,
   4282	.last_pixel_inc_missing	=	true,
   4283};
   4284
   4285static const struct dispc_features omap34xx_rev1_0_dispc_feats = {
   4286	.sw_start		=	5,
   4287	.fp_start		=	15,
   4288	.bp_start		=	27,
   4289	.sw_max			=	64,
   4290	.vp_max			=	255,
   4291	.hp_max			=	256,
   4292	.mgr_width_start	=	10,
   4293	.mgr_height_start	=	26,
   4294	.mgr_width_max		=	2048,
   4295	.mgr_height_max		=	2048,
   4296	.ovl_width_max		=	2048,
   4297	.ovl_height_max		=	2048,
   4298	.max_lcd_pclk		=	173000000,
   4299	.max_tv_pclk		=	59000000,
   4300	.max_downscale		=	4,
   4301	.max_line_width		=	1024,
   4302	.min_pcd		=	1,
   4303	.calc_scaling		=	dispc_ovl_calc_scaling_34xx,
   4304	.calc_core_clk		=	calc_core_clk_34xx,
   4305	.num_fifos		=	3,
   4306	.features		=	omap3_dispc_features_list,
   4307	.num_features		=	ARRAY_SIZE(omap3_dispc_features_list),
   4308	.reg_fields		=	omap3_dispc_reg_fields,
   4309	.num_reg_fields		=	ARRAY_SIZE(omap3_dispc_reg_fields),
   4310	.overlay_caps		=	omap3430_dispc_overlay_caps,
   4311	.supported_color_modes	=	omap3_dispc_supported_color_modes,
   4312	.supported_scaler_color_modes = omap3_dispc_supported_scaler_color_modes,
   4313	.num_mgrs		=	2,
   4314	.num_ovls		=	3,
   4315	.buffer_size_unit	=	1,
   4316	.burst_size_unit	=	8,
   4317	.no_framedone_tv	=	true,
   4318	.set_max_preload	=	false,
   4319	.last_pixel_inc_missing	=	true,
   4320};
   4321
   4322static const struct dispc_features omap34xx_rev3_0_dispc_feats = {
   4323	.sw_start		=	7,
   4324	.fp_start		=	19,
   4325	.bp_start		=	31,
   4326	.sw_max			=	256,
   4327	.vp_max			=	4095,
   4328	.hp_max			=	4096,
   4329	.mgr_width_start	=	10,
   4330	.mgr_height_start	=	26,
   4331	.mgr_width_max		=	2048,
   4332	.mgr_height_max		=	2048,
   4333	.ovl_width_max		=	2048,
   4334	.ovl_height_max		=	2048,
   4335	.max_lcd_pclk		=	173000000,
   4336	.max_tv_pclk		=	59000000,
   4337	.max_downscale		=	4,
   4338	.max_line_width		=	1024,
   4339	.min_pcd		=	1,
   4340	.calc_scaling		=	dispc_ovl_calc_scaling_34xx,
   4341	.calc_core_clk		=	calc_core_clk_34xx,
   4342	.num_fifos		=	3,
   4343	.features		=	omap3_dispc_features_list,
   4344	.num_features		=	ARRAY_SIZE(omap3_dispc_features_list),
   4345	.reg_fields		=	omap3_dispc_reg_fields,
   4346	.num_reg_fields		=	ARRAY_SIZE(omap3_dispc_reg_fields),
   4347	.overlay_caps		=	omap3430_dispc_overlay_caps,
   4348	.supported_color_modes	=	omap3_dispc_supported_color_modes,
   4349	.supported_scaler_color_modes = omap3_dispc_supported_scaler_color_modes,
   4350	.num_mgrs		=	2,
   4351	.num_ovls		=	3,
   4352	.buffer_size_unit	=	1,
   4353	.burst_size_unit	=	8,
   4354	.no_framedone_tv	=	true,
   4355	.set_max_preload	=	false,
   4356	.last_pixel_inc_missing	=	true,
   4357};
   4358
   4359static const struct dispc_features omap36xx_dispc_feats = {
   4360	.sw_start		=	7,
   4361	.fp_start		=	19,
   4362	.bp_start		=	31,
   4363	.sw_max			=	256,
   4364	.vp_max			=	4095,
   4365	.hp_max			=	4096,
   4366	.mgr_width_start	=	10,
   4367	.mgr_height_start	=	26,
   4368	.mgr_width_max		=	2048,
   4369	.mgr_height_max		=	2048,
   4370	.ovl_width_max		=	2048,
   4371	.ovl_height_max		=	2048,
   4372	.max_lcd_pclk		=	173000000,
   4373	.max_tv_pclk		=	59000000,
   4374	.max_downscale		=	4,
   4375	.max_line_width		=	1024,
   4376	.min_pcd		=	1,
   4377	.calc_scaling		=	dispc_ovl_calc_scaling_34xx,
   4378	.calc_core_clk		=	calc_core_clk_34xx,
   4379	.num_fifos		=	3,
   4380	.features		=	omap3_dispc_features_list,
   4381	.num_features		=	ARRAY_SIZE(omap3_dispc_features_list),
   4382	.reg_fields		=	omap3_dispc_reg_fields,
   4383	.num_reg_fields		=	ARRAY_SIZE(omap3_dispc_reg_fields),
   4384	.overlay_caps		=	omap3630_dispc_overlay_caps,
   4385	.supported_color_modes	=	omap3_dispc_supported_color_modes,
   4386	.supported_scaler_color_modes = omap3_dispc_supported_scaler_color_modes,
   4387	.num_mgrs		=	2,
   4388	.num_ovls		=	3,
   4389	.buffer_size_unit	=	1,
   4390	.burst_size_unit	=	8,
   4391	.no_framedone_tv	=	true,
   4392	.set_max_preload	=	false,
   4393	.last_pixel_inc_missing	=	true,
   4394};
   4395
   4396static const struct dispc_features am43xx_dispc_feats = {
   4397	.sw_start		=	7,
   4398	.fp_start		=	19,
   4399	.bp_start		=	31,
   4400	.sw_max			=	256,
   4401	.vp_max			=	4095,
   4402	.hp_max			=	4096,
   4403	.mgr_width_start	=	10,
   4404	.mgr_height_start	=	26,
   4405	.mgr_width_max		=	2048,
   4406	.mgr_height_max		=	2048,
   4407	.ovl_width_max		=	2048,
   4408	.ovl_height_max		=	2048,
   4409	.max_lcd_pclk		=	173000000,
   4410	.max_tv_pclk		=	59000000,
   4411	.max_downscale		=	4,
   4412	.max_line_width		=	1024,
   4413	.min_pcd		=	1,
   4414	.calc_scaling		=	dispc_ovl_calc_scaling_34xx,
   4415	.calc_core_clk		=	calc_core_clk_34xx,
   4416	.num_fifos		=	3,
   4417	.features		=	am43xx_dispc_features_list,
   4418	.num_features		=	ARRAY_SIZE(am43xx_dispc_features_list),
   4419	.reg_fields		=	omap3_dispc_reg_fields,
   4420	.num_reg_fields		=	ARRAY_SIZE(omap3_dispc_reg_fields),
   4421	.overlay_caps		=	omap3430_dispc_overlay_caps,
   4422	.supported_color_modes	=	omap3_dispc_supported_color_modes,
   4423	.supported_scaler_color_modes = omap3_dispc_supported_scaler_color_modes,
   4424	.num_mgrs		=	1,
   4425	.num_ovls		=	3,
   4426	.buffer_size_unit	=	1,
   4427	.burst_size_unit	=	8,
   4428	.no_framedone_tv	=	true,
   4429	.set_max_preload	=	false,
   4430	.last_pixel_inc_missing	=	true,
   4431};
   4432
   4433static const struct dispc_features omap44xx_dispc_feats = {
   4434	.sw_start		=	7,
   4435	.fp_start		=	19,
   4436	.bp_start		=	31,
   4437	.sw_max			=	256,
   4438	.vp_max			=	4095,
   4439	.hp_max			=	4096,
   4440	.mgr_width_start	=	10,
   4441	.mgr_height_start	=	26,
   4442	.mgr_width_max		=	2048,
   4443	.mgr_height_max		=	2048,
   4444	.ovl_width_max		=	2048,
   4445	.ovl_height_max		=	2048,
   4446	.max_lcd_pclk		=	170000000,
   4447	.max_tv_pclk		=	185625000,
   4448	.max_downscale		=	4,
   4449	.max_line_width		=	2048,
   4450	.min_pcd		=	1,
   4451	.calc_scaling		=	dispc_ovl_calc_scaling_44xx,
   4452	.calc_core_clk		=	calc_core_clk_44xx,
   4453	.num_fifos		=	5,
   4454	.features		=	omap4_dispc_features_list,
   4455	.num_features		=	ARRAY_SIZE(omap4_dispc_features_list),
   4456	.reg_fields		=	omap4_dispc_reg_fields,
   4457	.num_reg_fields		=	ARRAY_SIZE(omap4_dispc_reg_fields),
   4458	.overlay_caps		=	omap4_dispc_overlay_caps,
   4459	.supported_color_modes	=	omap4_dispc_supported_color_modes,
   4460	.num_mgrs		=	3,
   4461	.num_ovls		=	4,
   4462	.buffer_size_unit	=	16,
   4463	.burst_size_unit	=	16,
   4464	.gfx_fifo_workaround	=	true,
   4465	.set_max_preload	=	true,
   4466	.supports_sync_align	=	true,
   4467	.has_writeback		=	true,
   4468	.supports_double_pixel	=	true,
   4469	.reverse_ilace_field_order =	true,
   4470	.has_gamma_table	=	true,
   4471	.has_gamma_i734_bug	=	true,
   4472};
   4473
   4474static const struct dispc_features omap54xx_dispc_feats = {
   4475	.sw_start		=	7,
   4476	.fp_start		=	19,
   4477	.bp_start		=	31,
   4478	.sw_max			=	256,
   4479	.vp_max			=	4095,
   4480	.hp_max			=	4096,
   4481	.mgr_width_start	=	11,
   4482	.mgr_height_start	=	27,
   4483	.mgr_width_max		=	4096,
   4484	.mgr_height_max		=	4096,
   4485	.ovl_width_max		=	2048,
   4486	.ovl_height_max		=	4096,
   4487	.max_lcd_pclk		=	170000000,
   4488	.max_tv_pclk		=	192000000,
   4489	.max_downscale		=	4,
   4490	.max_line_width		=	2048,
   4491	.min_pcd		=	1,
   4492	.calc_scaling		=	dispc_ovl_calc_scaling_44xx,
   4493	.calc_core_clk		=	calc_core_clk_44xx,
   4494	.num_fifos		=	5,
   4495	.features		=	omap5_dispc_features_list,
   4496	.num_features		=	ARRAY_SIZE(omap5_dispc_features_list),
   4497	.reg_fields		=	omap4_dispc_reg_fields,
   4498	.num_reg_fields		=	ARRAY_SIZE(omap4_dispc_reg_fields),
   4499	.overlay_caps		=	omap4_dispc_overlay_caps,
   4500	.supported_color_modes	=	omap4_dispc_supported_color_modes,
   4501	.num_mgrs		=	4,
   4502	.num_ovls		=	4,
   4503	.buffer_size_unit	=	16,
   4504	.burst_size_unit	=	16,
   4505	.gfx_fifo_workaround	=	true,
   4506	.mstandby_workaround	=	true,
   4507	.set_max_preload	=	true,
   4508	.supports_sync_align	=	true,
   4509	.has_writeback		=	true,
   4510	.supports_double_pixel	=	true,
   4511	.reverse_ilace_field_order =	true,
   4512	.has_gamma_table	=	true,
   4513	.has_gamma_i734_bug	=	true,
   4514};
   4515
   4516static irqreturn_t dispc_irq_handler(int irq, void *arg)
   4517{
   4518	struct dispc_device *dispc = arg;
   4519
   4520	if (!dispc->is_enabled)
   4521		return IRQ_NONE;
   4522
   4523	return dispc->user_handler(irq, dispc->user_data);
   4524}
   4525
   4526int dispc_request_irq(struct dispc_device *dispc, irq_handler_t handler,
   4527			     void *dev_id)
   4528{
   4529	int r;
   4530
   4531	if (dispc->user_handler != NULL)
   4532		return -EBUSY;
   4533
   4534	dispc->user_handler = handler;
   4535	dispc->user_data = dev_id;
   4536
   4537	/* ensure the dispc_irq_handler sees the values above */
   4538	smp_wmb();
   4539
   4540	r = devm_request_irq(&dispc->pdev->dev, dispc->irq, dispc_irq_handler,
   4541			     IRQF_SHARED, "OMAP DISPC", dispc);
   4542	if (r) {
   4543		dispc->user_handler = NULL;
   4544		dispc->user_data = NULL;
   4545	}
   4546
   4547	return r;
   4548}
   4549
   4550void dispc_free_irq(struct dispc_device *dispc, void *dev_id)
   4551{
   4552	devm_free_irq(&dispc->pdev->dev, dispc->irq, dispc);
   4553
   4554	dispc->user_handler = NULL;
   4555	dispc->user_data = NULL;
   4556}
   4557
   4558u32 dispc_get_memory_bandwidth_limit(struct dispc_device *dispc)
   4559{
   4560	u32 limit = 0;
   4561
   4562	/* Optional maximum memory bandwidth */
   4563	of_property_read_u32(dispc->pdev->dev.of_node, "max-memory-bandwidth",
   4564			     &limit);
   4565
   4566	return limit;
   4567}
   4568
   4569/*
   4570 * Workaround for errata i734 in DSS dispc
   4571 *  - LCD1 Gamma Correction Is Not Working When GFX Pipe Is Disabled
   4572 *
   4573 * For gamma tables to work on LCD1 the GFX plane has to be used at
   4574 * least once after DSS HW has come out of reset. The workaround
   4575 * sets up a minimal LCD setup with GFX plane and waits for one
   4576 * vertical sync irq before disabling the setup and continuing with
   4577 * the context restore. The physical outputs are gated during the
   4578 * operation. This workaround requires that gamma table's LOADMODE
   4579 * is set to 0x2 in DISPC_CONTROL1 register.
   4580 *
   4581 * For details see:
   4582 * OMAP543x Multimedia Device Silicon Revision 2.0 Silicon Errata
   4583 * Literature Number: SWPZ037E
   4584 * Or some other relevant errata document for the DSS IP version.
   4585 */
   4586
   4587static const struct dispc_errata_i734_data {
   4588	struct videomode vm;
   4589	struct omap_overlay_info ovli;
   4590	struct omap_overlay_manager_info mgri;
   4591	struct dss_lcd_mgr_config lcd_conf;
   4592} i734 = {
   4593	.vm = {
   4594		.hactive = 8, .vactive = 1,
   4595		.pixelclock = 16000000,
   4596		.hsync_len = 8, .hfront_porch = 4, .hback_porch = 4,
   4597		.vsync_len = 1, .vfront_porch = 1, .vback_porch = 1,
   4598
   4599		.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
   4600			 DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_POSEDGE |
   4601			 DISPLAY_FLAGS_PIXDATA_POSEDGE,
   4602	},
   4603	.ovli = {
   4604		.screen_width = 1,
   4605		.width = 1, .height = 1,
   4606		.fourcc = DRM_FORMAT_XRGB8888,
   4607		.rotation = DRM_MODE_ROTATE_0,
   4608		.rotation_type = OMAP_DSS_ROT_NONE,
   4609		.pos_x = 0, .pos_y = 0,
   4610		.out_width = 0, .out_height = 0,
   4611		.global_alpha = 0xff,
   4612		.pre_mult_alpha = 0,
   4613		.zorder = 0,
   4614	},
   4615	.mgri = {
   4616		.default_color = 0,
   4617		.trans_enabled = false,
   4618		.partial_alpha_enabled = false,
   4619		.cpr_enable = false,
   4620	},
   4621	.lcd_conf = {
   4622		.io_pad_mode = DSS_IO_PAD_MODE_BYPASS,
   4623		.stallmode = false,
   4624		.fifohandcheck = false,
   4625		.clock_info = {
   4626			.lck_div = 1,
   4627			.pck_div = 2,
   4628		},
   4629		.video_port_width = 24,
   4630		.lcden_sig_polarity = 0,
   4631	},
   4632};
   4633
   4634static struct i734_buf {
   4635	size_t size;
   4636	dma_addr_t paddr;
   4637	void *vaddr;
   4638} i734_buf;
   4639
   4640static int dispc_errata_i734_wa_init(struct dispc_device *dispc)
   4641{
   4642	if (!dispc->feat->has_gamma_i734_bug)
   4643		return 0;
   4644
   4645	i734_buf.size = i734.ovli.width * i734.ovli.height *
   4646		color_mode_to_bpp(i734.ovli.fourcc) / 8;
   4647
   4648	i734_buf.vaddr = dma_alloc_wc(&dispc->pdev->dev, i734_buf.size,
   4649				      &i734_buf.paddr, GFP_KERNEL);
   4650	if (!i734_buf.vaddr) {
   4651		dev_err(&dispc->pdev->dev, "%s: dma_alloc_wc failed\n",
   4652			__func__);
   4653		return -ENOMEM;
   4654	}
   4655
   4656	return 0;
   4657}
   4658
   4659static void dispc_errata_i734_wa_fini(struct dispc_device *dispc)
   4660{
   4661	if (!dispc->feat->has_gamma_i734_bug)
   4662		return;
   4663
   4664	dma_free_wc(&dispc->pdev->dev, i734_buf.size, i734_buf.vaddr,
   4665		    i734_buf.paddr);
   4666}
   4667
   4668static void dispc_errata_i734_wa(struct dispc_device *dispc)
   4669{
   4670	u32 framedone_irq = dispc_mgr_get_framedone_irq(dispc,
   4671							OMAP_DSS_CHANNEL_LCD);
   4672	struct omap_overlay_info ovli;
   4673	struct dss_lcd_mgr_config lcd_conf;
   4674	u32 gatestate;
   4675	unsigned int count;
   4676
   4677	if (!dispc->feat->has_gamma_i734_bug)
   4678		return;
   4679
   4680	gatestate = REG_GET(dispc, DISPC_CONFIG, 8, 4);
   4681
   4682	ovli = i734.ovli;
   4683	ovli.paddr = i734_buf.paddr;
   4684	lcd_conf = i734.lcd_conf;
   4685
   4686	/* Gate all LCD1 outputs */
   4687	REG_FLD_MOD(dispc, DISPC_CONFIG, 0x1f, 8, 4);
   4688
   4689	/* Setup and enable GFX plane */
   4690	dispc_ovl_setup(dispc, OMAP_DSS_GFX, &ovli, &i734.vm, false,
   4691			OMAP_DSS_CHANNEL_LCD);
   4692	dispc_ovl_enable(dispc, OMAP_DSS_GFX, true);
   4693
   4694	/* Set up and enable display manager for LCD1 */
   4695	dispc_mgr_setup(dispc, OMAP_DSS_CHANNEL_LCD, &i734.mgri);
   4696	dispc_calc_clock_rates(dispc, dss_get_dispc_clk_rate(dispc->dss),
   4697			       &lcd_conf.clock_info);
   4698	dispc_mgr_set_lcd_config(dispc, OMAP_DSS_CHANNEL_LCD, &lcd_conf);
   4699	dispc_mgr_set_timings(dispc, OMAP_DSS_CHANNEL_LCD, &i734.vm);
   4700
   4701	dispc_clear_irqstatus(dispc, framedone_irq);
   4702
   4703	/* Enable and shut the channel to produce just one frame */
   4704	dispc_mgr_enable(dispc, OMAP_DSS_CHANNEL_LCD, true);
   4705	dispc_mgr_enable(dispc, OMAP_DSS_CHANNEL_LCD, false);
   4706
   4707	/* Busy wait for framedone. We can't fiddle with irq handlers
   4708	 * in PM resume. Typically the loop runs less than 5 times and
   4709	 * waits less than a micro second.
   4710	 */
   4711	count = 0;
   4712	while (!(dispc_read_irqstatus(dispc) & framedone_irq)) {
   4713		if (count++ > 10000) {
   4714			dev_err(&dispc->pdev->dev, "%s: framedone timeout\n",
   4715				__func__);
   4716			break;
   4717		}
   4718	}
   4719	dispc_ovl_enable(dispc, OMAP_DSS_GFX, false);
   4720
   4721	/* Clear all irq bits before continuing */
   4722	dispc_clear_irqstatus(dispc, 0xffffffff);
   4723
   4724	/* Restore the original state to LCD1 output gates */
   4725	REG_FLD_MOD(dispc, DISPC_CONFIG, gatestate, 8, 4);
   4726}
   4727
   4728/* DISPC HW IP initialisation */
   4729static const struct of_device_id dispc_of_match[] = {
   4730	{ .compatible = "ti,omap2-dispc", .data = &omap24xx_dispc_feats },
   4731	{ .compatible = "ti,omap3-dispc", .data = &omap36xx_dispc_feats },
   4732	{ .compatible = "ti,omap4-dispc", .data = &omap44xx_dispc_feats },
   4733	{ .compatible = "ti,omap5-dispc", .data = &omap54xx_dispc_feats },
   4734	{ .compatible = "ti,dra7-dispc",  .data = &omap54xx_dispc_feats },
   4735	{},
   4736};
   4737
   4738static const struct soc_device_attribute dispc_soc_devices[] = {
   4739	{ .machine = "OMAP3[45]*",
   4740	  .revision = "ES[12].?",	.data = &omap34xx_rev1_0_dispc_feats },
   4741	{ .machine = "OMAP3[45]*",	.data = &omap34xx_rev3_0_dispc_feats },
   4742	{ .machine = "AM35*",		.data = &omap34xx_rev3_0_dispc_feats },
   4743	{ .machine = "AM43*",		.data = &am43xx_dispc_feats },
   4744	{ /* sentinel */ }
   4745};
   4746
   4747static int dispc_bind(struct device *dev, struct device *master, void *data)
   4748{
   4749	struct platform_device *pdev = to_platform_device(dev);
   4750	const struct soc_device_attribute *soc;
   4751	struct dss_device *dss = dss_get_device(master);
   4752	struct dispc_device *dispc;
   4753	u32 rev;
   4754	int r = 0;
   4755	struct device_node *np = pdev->dev.of_node;
   4756
   4757	dispc = kzalloc(sizeof(*dispc), GFP_KERNEL);
   4758	if (!dispc)
   4759		return -ENOMEM;
   4760
   4761	dispc->pdev = pdev;
   4762	platform_set_drvdata(pdev, dispc);
   4763	dispc->dss = dss;
   4764
   4765	/*
   4766	 * The OMAP3-based models can't be told apart using the compatible
   4767	 * string, use SoC device matching.
   4768	 */
   4769	soc = soc_device_match(dispc_soc_devices);
   4770	if (soc)
   4771		dispc->feat = soc->data;
   4772	else
   4773		dispc->feat = of_match_device(dispc_of_match, &pdev->dev)->data;
   4774
   4775	r = dispc_errata_i734_wa_init(dispc);
   4776	if (r)
   4777		goto err_free;
   4778
   4779	dispc->base = devm_platform_ioremap_resource(pdev, 0);
   4780	if (IS_ERR(dispc->base)) {
   4781		r = PTR_ERR(dispc->base);
   4782		goto err_free;
   4783	}
   4784
   4785	dispc->irq = platform_get_irq(dispc->pdev, 0);
   4786	if (dispc->irq < 0) {
   4787		DSSERR("platform_get_irq failed\n");
   4788		r = -ENODEV;
   4789		goto err_free;
   4790	}
   4791
   4792	if (np && of_property_read_bool(np, "syscon-pol")) {
   4793		dispc->syscon_pol = syscon_regmap_lookup_by_phandle(np, "syscon-pol");
   4794		if (IS_ERR(dispc->syscon_pol)) {
   4795			dev_err(&pdev->dev, "failed to get syscon-pol regmap\n");
   4796			r = PTR_ERR(dispc->syscon_pol);
   4797			goto err_free;
   4798		}
   4799
   4800		if (of_property_read_u32_index(np, "syscon-pol", 1,
   4801				&dispc->syscon_pol_offset)) {
   4802			dev_err(&pdev->dev, "failed to get syscon-pol offset\n");
   4803			r = -EINVAL;
   4804			goto err_free;
   4805		}
   4806	}
   4807
   4808	r = dispc_init_gamma_tables(dispc);
   4809	if (r)
   4810		goto err_free;
   4811
   4812	pm_runtime_enable(&pdev->dev);
   4813
   4814	r = dispc_runtime_get(dispc);
   4815	if (r)
   4816		goto err_runtime_get;
   4817
   4818	_omap_dispc_initial_config(dispc);
   4819
   4820	rev = dispc_read_reg(dispc, DISPC_REVISION);
   4821	dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
   4822	       FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
   4823
   4824	dispc_runtime_put(dispc);
   4825
   4826	dss->dispc = dispc;
   4827
   4828	dispc->debugfs = dss_debugfs_create_file(dss, "dispc", dispc_dump_regs,
   4829						 dispc);
   4830
   4831	return 0;
   4832
   4833err_runtime_get:
   4834	pm_runtime_disable(&pdev->dev);
   4835err_free:
   4836	kfree(dispc);
   4837	return r;
   4838}
   4839
   4840static void dispc_unbind(struct device *dev, struct device *master, void *data)
   4841{
   4842	struct dispc_device *dispc = dev_get_drvdata(dev);
   4843	struct dss_device *dss = dispc->dss;
   4844
   4845	dss_debugfs_remove_file(dispc->debugfs);
   4846
   4847	dss->dispc = NULL;
   4848
   4849	pm_runtime_disable(dev);
   4850
   4851	dispc_errata_i734_wa_fini(dispc);
   4852
   4853	kfree(dispc);
   4854}
   4855
   4856static const struct component_ops dispc_component_ops = {
   4857	.bind	= dispc_bind,
   4858	.unbind	= dispc_unbind,
   4859};
   4860
   4861static int dispc_probe(struct platform_device *pdev)
   4862{
   4863	return component_add(&pdev->dev, &dispc_component_ops);
   4864}
   4865
   4866static int dispc_remove(struct platform_device *pdev)
   4867{
   4868	component_del(&pdev->dev, &dispc_component_ops);
   4869	return 0;
   4870}
   4871
   4872static __maybe_unused int dispc_runtime_suspend(struct device *dev)
   4873{
   4874	struct dispc_device *dispc = dev_get_drvdata(dev);
   4875
   4876	dispc->is_enabled = false;
   4877	/* ensure the dispc_irq_handler sees the is_enabled value */
   4878	smp_wmb();
   4879	/* wait for current handler to finish before turning the DISPC off */
   4880	synchronize_irq(dispc->irq);
   4881
   4882	dispc_save_context(dispc);
   4883
   4884	return 0;
   4885}
   4886
   4887static __maybe_unused int dispc_runtime_resume(struct device *dev)
   4888{
   4889	struct dispc_device *dispc = dev_get_drvdata(dev);
   4890
   4891	/*
   4892	 * The reset value for load mode is 0 (OMAP_DSS_LOAD_CLUT_AND_FRAME)
   4893	 * but we always initialize it to 2 (OMAP_DSS_LOAD_FRAME_ONLY) in
   4894	 * _omap_dispc_initial_config(). We can thus use it to detect if
   4895	 * we have lost register context.
   4896	 */
   4897	if (REG_GET(dispc, DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) {
   4898		_omap_dispc_initial_config(dispc);
   4899
   4900		dispc_errata_i734_wa(dispc);
   4901
   4902		dispc_restore_context(dispc);
   4903
   4904		dispc_restore_gamma_tables(dispc);
   4905	}
   4906
   4907	dispc->is_enabled = true;
   4908	/* ensure the dispc_irq_handler sees the is_enabled value */
   4909	smp_wmb();
   4910
   4911	return 0;
   4912}
   4913
   4914static const struct dev_pm_ops dispc_pm_ops = {
   4915	SET_RUNTIME_PM_OPS(dispc_runtime_suspend, dispc_runtime_resume, NULL)
   4916	SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
   4917};
   4918
   4919struct platform_driver omap_dispchw_driver = {
   4920	.probe		= dispc_probe,
   4921	.remove         = dispc_remove,
   4922	.driver         = {
   4923		.name   = "omapdss_dispc",
   4924		.pm	= &dispc_pm_ops,
   4925		.of_match_table = dispc_of_match,
   4926		.suppress_bind_attrs = true,
   4927	},
   4928};