Home | History | Annotate | Download | only in video
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Porting to u-boot:
      4  *
      5  * (C) Copyright 2010
      6  * Stefano Babic, DENX Software Engineering, sbabic (at) denx.de
      7  *
      8  * Linux IPU driver for MX51:
      9  *
     10  * (C) Copyright 2005-2010 Freescale Semiconductor, Inc.
     11  */
     12 
     13 /* #define DEBUG */
     14 
     15 #include <common.h>
     16 #include <linux/types.h>
     17 #include <linux/errno.h>
     18 #include <asm/io.h>
     19 #include <asm/arch/imx-regs.h>
     20 #include <asm/arch/sys_proto.h>
     21 #include "ipu.h"
     22 #include "ipu_regs.h"
     23 
     24 enum csc_type_t {
     25 	RGB2YUV = 0,
     26 	YUV2RGB,
     27 	RGB2RGB,
     28 	YUV2YUV,
     29 	CSC_NONE,
     30 	CSC_NUM
     31 };
     32 
     33 struct dp_csc_param_t {
     34 	int mode;
     35 	const int (*coeff)[5][3];
     36 };
     37 
     38 #define SYNC_WAVE 0
     39 
     40 /* DC display ID assignments */
     41 #define DC_DISP_ID_SYNC(di)	(di)
     42 #define DC_DISP_ID_SERIAL	2
     43 #define DC_DISP_ID_ASYNC	3
     44 
     45 int dmfc_type_setup;
     46 static int dmfc_size_28, dmfc_size_29, dmfc_size_24, dmfc_size_27, dmfc_size_23;
     47 int g_di1_tvout;
     48 
     49 extern struct clk *g_ipu_clk;
     50 extern struct clk *g_ldb_clk;
     51 extern struct clk *g_di_clk[2];
     52 extern struct clk *g_pixel_clk[2];
     53 
     54 extern unsigned char g_ipu_clk_enabled;
     55 extern unsigned char g_dc_di_assignment[];
     56 
     57 void ipu_dmfc_init(int dmfc_type, int first)
     58 {
     59 	u32 dmfc_wr_chan, dmfc_dp_chan;
     60 
     61 	if (first) {
     62 		if (dmfc_type_setup > dmfc_type)
     63 			dmfc_type = dmfc_type_setup;
     64 		else
     65 			dmfc_type_setup = dmfc_type;
     66 
     67 		/* disable DMFC-IC channel*/
     68 		__raw_writel(0x2, DMFC_IC_CTRL);
     69 	} else if (dmfc_type_setup >= DMFC_HIGH_RESOLUTION_DC) {
     70 		printf("DMFC high resolution has set, will not change\n");
     71 		return;
     72 	} else
     73 		dmfc_type_setup = dmfc_type;
     74 
     75 	if (dmfc_type == DMFC_HIGH_RESOLUTION_DC) {
     76 		/* 1 - segment 0~3;
     77 		 * 5B - segement 4, 5;
     78 		 * 5F - segement 6, 7;
     79 		 * 1C, 2C and 6B, 6F unused;
     80 		 */
     81 		debug("IPU DMFC DC HIGH RES: 1(0~3), 5B(4,5), 5F(6,7)\n");
     82 		dmfc_wr_chan = 0x00000088;
     83 		dmfc_dp_chan = 0x00009694;
     84 		dmfc_size_28 = 256 * 4;
     85 		dmfc_size_29 = 0;
     86 		dmfc_size_24 = 0;
     87 		dmfc_size_27 = 128 * 4;
     88 		dmfc_size_23 = 128 * 4;
     89 	} else if (dmfc_type == DMFC_HIGH_RESOLUTION_DP) {
     90 		/* 1 - segment 0, 1;
     91 		 * 5B - segement 2~5;
     92 		 * 5F - segement 6,7;
     93 		 * 1C, 2C and 6B, 6F unused;
     94 		 */
     95 		debug("IPU DMFC DP HIGH RES: 1(0,1), 5B(2~5), 5F(6,7)\n");
     96 		dmfc_wr_chan = 0x00000090;
     97 		dmfc_dp_chan = 0x0000968a;
     98 		dmfc_size_28 = 128 * 4;
     99 		dmfc_size_29 = 0;
    100 		dmfc_size_24 = 0;
    101 		dmfc_size_27 = 128 * 4;
    102 		dmfc_size_23 = 256 * 4;
    103 	} else if (dmfc_type == DMFC_HIGH_RESOLUTION_ONLY_DP) {
    104 		/* 5B - segement 0~3;
    105 		 * 5F - segement 4~7;
    106 		 * 1, 1C, 2C and 6B, 6F unused;
    107 		 */
    108 		debug("IPU DMFC ONLY-DP HIGH RES: 5B(0~3), 5F(4~7)\n");
    109 		dmfc_wr_chan = 0x00000000;
    110 		dmfc_dp_chan = 0x00008c88;
    111 		dmfc_size_28 = 0;
    112 		dmfc_size_29 = 0;
    113 		dmfc_size_24 = 0;
    114 		dmfc_size_27 = 256 * 4;
    115 		dmfc_size_23 = 256 * 4;
    116 	} else {
    117 		/* 1 - segment 0, 1;
    118 		 * 5B - segement 4, 5;
    119 		 * 5F - segement 6, 7;
    120 		 * 1C, 2C and 6B, 6F unused;
    121 		 */
    122 		debug("IPU DMFC NORMAL mode: 1(0~1), 5B(4,5), 5F(6,7)\n");
    123 		dmfc_wr_chan = 0x00000090;
    124 		dmfc_dp_chan = 0x00009694;
    125 		dmfc_size_28 = 128 * 4;
    126 		dmfc_size_29 = 0;
    127 		dmfc_size_24 = 0;
    128 		dmfc_size_27 = 128 * 4;
    129 		dmfc_size_23 = 128 * 4;
    130 	}
    131 	__raw_writel(dmfc_wr_chan, DMFC_WR_CHAN);
    132 	__raw_writel(0x202020F6, DMFC_WR_CHAN_DEF);
    133 	__raw_writel(dmfc_dp_chan, DMFC_DP_CHAN);
    134 	/* Enable chan 5 watermark set at 5 bursts and clear at 7 bursts */
    135 	__raw_writel(0x2020F6F6, DMFC_DP_CHAN_DEF);
    136 }
    137 
    138 void ipu_dmfc_set_wait4eot(int dma_chan, int width)
    139 {
    140 	u32 dmfc_gen1 = __raw_readl(DMFC_GENERAL1);
    141 
    142 	if (width >= HIGH_RESOLUTION_WIDTH) {
    143 		if (dma_chan == 23)
    144 			ipu_dmfc_init(DMFC_HIGH_RESOLUTION_DP, 0);
    145 		else if (dma_chan == 28)
    146 			ipu_dmfc_init(DMFC_HIGH_RESOLUTION_DC, 0);
    147 	}
    148 
    149 	if (dma_chan == 23) { /*5B*/
    150 		if (dmfc_size_23 / width > 3)
    151 			dmfc_gen1 |= 1UL << 20;
    152 		else
    153 			dmfc_gen1 &= ~(1UL << 20);
    154 	} else if (dma_chan == 24) { /*6B*/
    155 		if (dmfc_size_24 / width > 1)
    156 			dmfc_gen1 |= 1UL << 22;
    157 		else
    158 			dmfc_gen1 &= ~(1UL << 22);
    159 	} else if (dma_chan == 27) { /*5F*/
    160 		if (dmfc_size_27 / width > 2)
    161 			dmfc_gen1 |= 1UL << 21;
    162 		else
    163 			dmfc_gen1 &= ~(1UL << 21);
    164 	} else if (dma_chan == 28) { /*1*/
    165 		if (dmfc_size_28 / width > 2)
    166 			dmfc_gen1 |= 1UL << 16;
    167 		else
    168 			dmfc_gen1 &= ~(1UL << 16);
    169 	} else if (dma_chan == 29) { /*6F*/
    170 		if (dmfc_size_29 / width > 1)
    171 			dmfc_gen1 |= 1UL << 23;
    172 		else
    173 			dmfc_gen1 &= ~(1UL << 23);
    174 	}
    175 
    176 	__raw_writel(dmfc_gen1, DMFC_GENERAL1);
    177 }
    178 
    179 static void ipu_di_data_wave_config(int di,
    180 				     int wave_gen,
    181 				     int access_size, int component_size)
    182 {
    183 	u32 reg;
    184 	reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
    185 	    (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
    186 	__raw_writel(reg, DI_DW_GEN(di, wave_gen));
    187 }
    188 
    189 static void ipu_di_data_pin_config(int di, int wave_gen, int di_pin, int set,
    190 				    int up, int down)
    191 {
    192 	u32 reg;
    193 
    194 	reg = __raw_readl(DI_DW_GEN(di, wave_gen));
    195 	reg &= ~(0x3 << (di_pin * 2));
    196 	reg |= set << (di_pin * 2);
    197 	__raw_writel(reg, DI_DW_GEN(di, wave_gen));
    198 
    199 	__raw_writel((down << 16) | up, DI_DW_SET(di, wave_gen, set));
    200 }
    201 
    202 static void ipu_di_sync_config(int di, int wave_gen,
    203 				int run_count, int run_src,
    204 				int offset_count, int offset_src,
    205 				int repeat_count, int cnt_clr_src,
    206 				int cnt_polarity_gen_en,
    207 				int cnt_polarity_clr_src,
    208 				int cnt_polarity_trigger_src,
    209 				int cnt_up, int cnt_down)
    210 {
    211 	u32 reg;
    212 
    213 	if ((run_count >= 0x1000) || (offset_count >= 0x1000) ||
    214 		(repeat_count >= 0x1000) ||
    215 		(cnt_up >= 0x400) || (cnt_down >= 0x400)) {
    216 		printf("DI%d counters out of range.\n", di);
    217 		return;
    218 	}
    219 
    220 	reg = (run_count << 19) | (++run_src << 16) |
    221 	    (offset_count << 3) | ++offset_src;
    222 	__raw_writel(reg, DI_SW_GEN0(di, wave_gen));
    223 	reg = (cnt_polarity_gen_en << 29) | (++cnt_clr_src << 25) |
    224 	    (++cnt_polarity_trigger_src << 12) | (++cnt_polarity_clr_src << 9);
    225 	reg |= (cnt_down << 16) | cnt_up;
    226 	if (repeat_count == 0) {
    227 		/* Enable auto reload */
    228 		reg |= 0x10000000;
    229 	}
    230 	__raw_writel(reg, DI_SW_GEN1(di, wave_gen));
    231 	reg = __raw_readl(DI_STP_REP(di, wave_gen));
    232 	reg &= ~(0xFFFF << (16 * ((wave_gen - 1) & 0x1)));
    233 	reg |= repeat_count << (16 * ((wave_gen - 1) & 0x1));
    234 	__raw_writel(reg, DI_STP_REP(di, wave_gen));
    235 }
    236 
    237 static void ipu_dc_map_config(int map, int byte_num, int offset, int mask)
    238 {
    239 	int ptr = map * 3 + byte_num;
    240 	u32 reg;
    241 
    242 	reg = __raw_readl(DC_MAP_CONF_VAL(ptr));
    243 	reg &= ~(0xFFFF << (16 * (ptr & 0x1)));
    244 	reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
    245 	__raw_writel(reg, DC_MAP_CONF_VAL(ptr));
    246 
    247 	reg = __raw_readl(DC_MAP_CONF_PTR(map));
    248 	reg &= ~(0x1F << ((16 * (map & 0x1)) + (5 * byte_num)));
    249 	reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
    250 	__raw_writel(reg, DC_MAP_CONF_PTR(map));
    251 }
    252 
    253 static void ipu_dc_map_clear(int map)
    254 {
    255 	u32 reg = __raw_readl(DC_MAP_CONF_PTR(map));
    256 	__raw_writel(reg & ~(0xFFFF << (16 * (map & 0x1))),
    257 		     DC_MAP_CONF_PTR(map));
    258 }
    259 
    260 static void ipu_dc_write_tmpl(int word, u32 opcode, u32 operand, int map,
    261 			       int wave, int glue, int sync)
    262 {
    263 	u32 reg;
    264 	int stop = 1;
    265 
    266 	reg = sync;
    267 	reg |= (glue << 4);
    268 	reg |= (++wave << 11);
    269 	reg |= (++map << 15);
    270 	reg |= (operand << 20) & 0xFFF00000;
    271 	__raw_writel(reg, ipu_dc_tmpl_reg + word * 2);
    272 
    273 	reg = (operand >> 12);
    274 	reg |= opcode << 4;
    275 	reg |= (stop << 9);
    276 	__raw_writel(reg, ipu_dc_tmpl_reg + word * 2 + 1);
    277 }
    278 
    279 static void ipu_dc_link_event(int chan, int event, int addr, int priority)
    280 {
    281 	u32 reg;
    282 
    283 	reg = __raw_readl(DC_RL_CH(chan, event));
    284 	reg &= ~(0xFFFF << (16 * (event & 0x1)));
    285 	reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
    286 	__raw_writel(reg, DC_RL_CH(chan, event));
    287 }
    288 
    289 /* Y = R *  1.200 + G *  2.343 + B *  .453 + 0.250;
    290  * U = R * -.672 + G * -1.328 + B *  2.000 + 512.250.;
    291  * V = R *  2.000 + G * -1.672 + B * -.328 + 512.250.;
    292  */
    293 static const int rgb2ycbcr_coeff[5][3] = {
    294 	{0x4D, 0x96, 0x1D},
    295 	{0x3D5, 0x3AB, 0x80},
    296 	{0x80, 0x395, 0x3EB},
    297 	{0x0000, 0x0200, 0x0200},	/* B0, B1, B2 */
    298 	{0x2, 0x2, 0x2},	/* S0, S1, S2 */
    299 };
    300 
    301 /* R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
    302  * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
    303  * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
    304  */
    305 static const int ycbcr2rgb_coeff[5][3] = {
    306 	{0x095, 0x000, 0x0CC},
    307 	{0x095, 0x3CE, 0x398},
    308 	{0x095, 0x0FF, 0x000},
    309 	{0x3E42, 0x010A, 0x3DD6},	/*B0,B1,B2 */
    310 	{0x1, 0x1, 0x1},	/*S0,S1,S2 */
    311 };
    312 
    313 #define mask_a(a) ((u32)(a) & 0x3FF)
    314 #define mask_b(b) ((u32)(b) & 0x3FFF)
    315 
    316 /* Pls keep S0, S1 and S2 as 0x2 by using this convertion */
    317 static int rgb_to_yuv(int n, int red, int green, int blue)
    318 {
    319 	int c;
    320 	c = red * rgb2ycbcr_coeff[n][0];
    321 	c += green * rgb2ycbcr_coeff[n][1];
    322 	c += blue * rgb2ycbcr_coeff[n][2];
    323 	c /= 16;
    324 	c += rgb2ycbcr_coeff[3][n] * 4;
    325 	c += 8;
    326 	c /= 16;
    327 	if (c < 0)
    328 		c = 0;
    329 	if (c > 255)
    330 		c = 255;
    331 	return c;
    332 }
    333 
    334 /*
    335  * Row is for BG:	RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
    336  * Column is for FG:	RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
    337  */
    338 static struct dp_csc_param_t dp_csc_array[CSC_NUM][CSC_NUM] = {
    339 	{
    340 		{DP_COM_CONF_CSC_DEF_BOTH, &rgb2ycbcr_coeff},
    341 		{0, 0},
    342 		{0, 0},
    343 		{DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff},
    344 		{DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff}
    345 	},
    346 	{
    347 		{0, 0},
    348 		{DP_COM_CONF_CSC_DEF_BOTH, &ycbcr2rgb_coeff},
    349 		{DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff},
    350 		{0, 0},
    351 		{DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff}
    352 	},
    353 	{
    354 		{0, 0},
    355 		{DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff},
    356 		{0, 0},
    357 		{0, 0},
    358 		{0, 0}
    359 	},
    360 	{
    361 		{DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff},
    362 		{0, 0},
    363 		{0, 0},
    364 		{0, 0},
    365 		{0, 0}
    366 	},
    367 	{
    368 		{DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff},
    369 		{DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff},
    370 		{0, 0},
    371 		{0, 0},
    372 		{0, 0}
    373 	}
    374 };
    375 
    376 static enum csc_type_t fg_csc_type = CSC_NONE, bg_csc_type = CSC_NONE;
    377 static int color_key_4rgb = 1;
    378 
    379 static void ipu_dp_csc_setup(int dp, struct dp_csc_param_t dp_csc_param,
    380 			unsigned char srm_mode_update)
    381 {
    382 	u32 reg;
    383 	const int (*coeff)[5][3];
    384 
    385 	if (dp_csc_param.mode >= 0) {
    386 		reg = __raw_readl(DP_COM_CONF());
    387 		reg &= ~DP_COM_CONF_CSC_DEF_MASK;
    388 		reg |= dp_csc_param.mode;
    389 		__raw_writel(reg, DP_COM_CONF());
    390 	}
    391 
    392 	coeff = dp_csc_param.coeff;
    393 
    394 	if (coeff) {
    395 		__raw_writel(mask_a((*coeff)[0][0]) |
    396 				(mask_a((*coeff)[0][1]) << 16), DP_CSC_A_0());
    397 		__raw_writel(mask_a((*coeff)[0][2]) |
    398 				(mask_a((*coeff)[1][0]) << 16), DP_CSC_A_1());
    399 		__raw_writel(mask_a((*coeff)[1][1]) |
    400 				(mask_a((*coeff)[1][2]) << 16), DP_CSC_A_2());
    401 		__raw_writel(mask_a((*coeff)[2][0]) |
    402 				(mask_a((*coeff)[2][1]) << 16), DP_CSC_A_3());
    403 		__raw_writel(mask_a((*coeff)[2][2]) |
    404 				(mask_b((*coeff)[3][0]) << 16) |
    405 				((*coeff)[4][0] << 30), DP_CSC_0());
    406 		__raw_writel(mask_b((*coeff)[3][1]) | ((*coeff)[4][1] << 14) |
    407 				(mask_b((*coeff)[3][2]) << 16) |
    408 				((*coeff)[4][2] << 30), DP_CSC_1());
    409 	}
    410 
    411 	if (srm_mode_update) {
    412 		reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
    413 		__raw_writel(reg, IPU_SRM_PRI2);
    414 	}
    415 }
    416 
    417 int ipu_dp_init(ipu_channel_t channel, uint32_t in_pixel_fmt,
    418 		 uint32_t out_pixel_fmt)
    419 {
    420 	int in_fmt, out_fmt;
    421 	int dp;
    422 	int partial = 0;
    423 	uint32_t reg;
    424 
    425 	if (channel == MEM_FG_SYNC) {
    426 		dp = DP_SYNC;
    427 		partial = 1;
    428 	} else if (channel == MEM_BG_SYNC) {
    429 		dp = DP_SYNC;
    430 		partial = 0;
    431 	} else if (channel == MEM_BG_ASYNC0) {
    432 		dp = DP_ASYNC0;
    433 		partial = 0;
    434 	} else {
    435 		return -EINVAL;
    436 	}
    437 
    438 	in_fmt = format_to_colorspace(in_pixel_fmt);
    439 	out_fmt = format_to_colorspace(out_pixel_fmt);
    440 
    441 	if (partial) {
    442 		if (in_fmt == RGB) {
    443 			if (out_fmt == RGB)
    444 				fg_csc_type = RGB2RGB;
    445 			else
    446 				fg_csc_type = RGB2YUV;
    447 		} else {
    448 			if (out_fmt == RGB)
    449 				fg_csc_type = YUV2RGB;
    450 			else
    451 				fg_csc_type = YUV2YUV;
    452 		}
    453 	} else {
    454 		if (in_fmt == RGB) {
    455 			if (out_fmt == RGB)
    456 				bg_csc_type = RGB2RGB;
    457 			else
    458 				bg_csc_type = RGB2YUV;
    459 		} else {
    460 			if (out_fmt == RGB)
    461 				bg_csc_type = YUV2RGB;
    462 			else
    463 				bg_csc_type = YUV2YUV;
    464 		}
    465 	}
    466 
    467 	/* Transform color key from rgb to yuv if CSC is enabled */
    468 	reg = __raw_readl(DP_COM_CONF());
    469 	if (color_key_4rgb && (reg & DP_COM_CONF_GWCKE) &&
    470 		(((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) ||
    471 		((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) ||
    472 		((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) ||
    473 		((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB)))) {
    474 		int red, green, blue;
    475 		int y, u, v;
    476 		uint32_t color_key = __raw_readl(DP_GRAPH_WIND_CTRL()) &
    477 			0xFFFFFFL;
    478 
    479 		debug("_ipu_dp_init color key 0x%x need change to yuv fmt!\n",
    480 			color_key);
    481 
    482 		red = (color_key >> 16) & 0xFF;
    483 		green = (color_key >> 8) & 0xFF;
    484 		blue = color_key & 0xFF;
    485 
    486 		y = rgb_to_yuv(0, red, green, blue);
    487 		u = rgb_to_yuv(1, red, green, blue);
    488 		v = rgb_to_yuv(2, red, green, blue);
    489 		color_key = (y << 16) | (u << 8) | v;
    490 
    491 		reg = __raw_readl(DP_GRAPH_WIND_CTRL()) & 0xFF000000L;
    492 		__raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL());
    493 		color_key_4rgb = 0;
    494 
    495 		debug("_ipu_dp_init color key change to yuv fmt 0x%x!\n",
    496 			color_key);
    497 	}
    498 
    499 	ipu_dp_csc_setup(dp, dp_csc_array[bg_csc_type][fg_csc_type], 1);
    500 
    501 	return 0;
    502 }
    503 
    504 void ipu_dp_uninit(ipu_channel_t channel)
    505 {
    506 	int dp;
    507 	int partial = 0;
    508 
    509 	if (channel == MEM_FG_SYNC) {
    510 		dp = DP_SYNC;
    511 		partial = 1;
    512 	} else if (channel == MEM_BG_SYNC) {
    513 		dp = DP_SYNC;
    514 		partial = 0;
    515 	} else if (channel == MEM_BG_ASYNC0) {
    516 		dp = DP_ASYNC0;
    517 		partial = 0;
    518 	} else {
    519 		return;
    520 	}
    521 
    522 	if (partial)
    523 		fg_csc_type = CSC_NONE;
    524 	else
    525 		bg_csc_type = CSC_NONE;
    526 
    527 	ipu_dp_csc_setup(dp, dp_csc_array[bg_csc_type][fg_csc_type], 0);
    528 }
    529 
    530 void ipu_dc_init(int dc_chan, int di, unsigned char interlaced)
    531 {
    532 	u32 reg = 0;
    533 
    534 	if ((dc_chan == 1) || (dc_chan == 5)) {
    535 		if (interlaced) {
    536 			ipu_dc_link_event(dc_chan, DC_EVT_NL, 0, 3);
    537 			ipu_dc_link_event(dc_chan, DC_EVT_EOL, 0, 2);
    538 			ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 0, 1);
    539 		} else {
    540 			if (di) {
    541 				ipu_dc_link_event(dc_chan, DC_EVT_NL, 2, 3);
    542 				ipu_dc_link_event(dc_chan, DC_EVT_EOL, 3, 2);
    543 				ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA,
    544 					4, 1);
    545 			} else {
    546 				ipu_dc_link_event(dc_chan, DC_EVT_NL, 5, 3);
    547 				ipu_dc_link_event(dc_chan, DC_EVT_EOL, 6, 2);
    548 				ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA,
    549 					7, 1);
    550 			}
    551 		}
    552 		ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0);
    553 		ipu_dc_link_event(dc_chan, DC_EVT_NFIELD, 0, 0);
    554 		ipu_dc_link_event(dc_chan, DC_EVT_EOF, 0, 0);
    555 		ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0);
    556 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0);
    557 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0);
    558 
    559 		reg = 0x2;
    560 		reg |= DC_DISP_ID_SYNC(di) << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
    561 		reg |= di << 2;
    562 		if (interlaced)
    563 			reg |= DC_WR_CH_CONF_FIELD_MODE;
    564 	} else if ((dc_chan == 8) || (dc_chan == 9)) {
    565 		/* async channels */
    566 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_0, 0x64, 1);
    567 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_1, 0x64, 1);
    568 
    569 		reg = 0x3;
    570 		reg |= DC_DISP_ID_SERIAL << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
    571 	}
    572 	__raw_writel(reg, DC_WR_CH_CONF(dc_chan));
    573 
    574 	__raw_writel(0x00000000, DC_WR_CH_ADDR(dc_chan));
    575 
    576 	__raw_writel(0x00000084, DC_GEN);
    577 }
    578 
    579 void ipu_dc_uninit(int dc_chan)
    580 {
    581 	if ((dc_chan == 1) || (dc_chan == 5)) {
    582 		ipu_dc_link_event(dc_chan, DC_EVT_NL, 0, 0);
    583 		ipu_dc_link_event(dc_chan, DC_EVT_EOL, 0, 0);
    584 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 0, 0);
    585 		ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0);
    586 		ipu_dc_link_event(dc_chan, DC_EVT_NFIELD, 0, 0);
    587 		ipu_dc_link_event(dc_chan, DC_EVT_EOF, 0, 0);
    588 		ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0);
    589 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0);
    590 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0);
    591 	} else if ((dc_chan == 8) || (dc_chan == 9)) {
    592 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_0, 0, 0);
    593 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_1, 0, 0);
    594 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_W_0, 0, 0);
    595 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_W_1, 0, 0);
    596 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_0, 0, 0);
    597 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_1, 0, 0);
    598 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_R_0, 0, 0);
    599 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_R_1, 0, 0);
    600 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_R_0, 0, 0);
    601 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_R_1, 0, 0);
    602 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_R_0, 0, 0);
    603 		ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_R_1, 0, 0);
    604 	}
    605 }
    606 
    607 void ipu_dp_dc_enable(ipu_channel_t channel)
    608 {
    609 	int di;
    610 	uint32_t reg;
    611 	uint32_t dc_chan;
    612 
    613 	if (channel == MEM_DC_SYNC)
    614 		dc_chan = 1;
    615 	else if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC))
    616 		dc_chan = 5;
    617 	else
    618 		return;
    619 
    620 	if (channel == MEM_FG_SYNC) {
    621 		/* Enable FG channel */
    622 		reg = __raw_readl(DP_COM_CONF());
    623 		__raw_writel(reg | DP_COM_CONF_FG_EN, DP_COM_CONF());
    624 
    625 		reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
    626 		__raw_writel(reg, IPU_SRM_PRI2);
    627 		return;
    628 	}
    629 
    630 	di = g_dc_di_assignment[dc_chan];
    631 
    632 	/* Make sure other DC sync channel is not assigned same DI */
    633 	reg = __raw_readl(DC_WR_CH_CONF(6 - dc_chan));
    634 	if ((di << 2) == (reg & DC_WR_CH_CONF_PROG_DI_ID)) {
    635 		reg &= ~DC_WR_CH_CONF_PROG_DI_ID;
    636 		reg |= di ? 0 : DC_WR_CH_CONF_PROG_DI_ID;
    637 		__raw_writel(reg, DC_WR_CH_CONF(6 - dc_chan));
    638 	}
    639 
    640 	reg = __raw_readl(DC_WR_CH_CONF(dc_chan));
    641 	reg |= 4 << DC_WR_CH_CONF_PROG_TYPE_OFFSET;
    642 	__raw_writel(reg, DC_WR_CH_CONF(dc_chan));
    643 
    644 	clk_enable(g_pixel_clk[di]);
    645 }
    646 
    647 static unsigned char dc_swap;
    648 
    649 void ipu_dp_dc_disable(ipu_channel_t channel, unsigned char swap)
    650 {
    651 	uint32_t reg;
    652 	uint32_t csc;
    653 	uint32_t dc_chan = 0;
    654 	int timeout = 50;
    655 	int irq = 0;
    656 
    657 	dc_swap = swap;
    658 
    659 	if (channel == MEM_DC_SYNC) {
    660 		dc_chan = 1;
    661 		irq = IPU_IRQ_DC_FC_1;
    662 	} else if (channel == MEM_BG_SYNC) {
    663 		dc_chan = 5;
    664 		irq = IPU_IRQ_DP_SF_END;
    665 	} else if (channel == MEM_FG_SYNC) {
    666 		/* Disable FG channel */
    667 		dc_chan = 5;
    668 
    669 		reg = __raw_readl(DP_COM_CONF());
    670 		csc = reg & DP_COM_CONF_CSC_DEF_MASK;
    671 		if (csc == DP_COM_CONF_CSC_DEF_FG)
    672 			reg &= ~DP_COM_CONF_CSC_DEF_MASK;
    673 
    674 		reg &= ~DP_COM_CONF_FG_EN;
    675 		__raw_writel(reg, DP_COM_CONF());
    676 
    677 		reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
    678 		__raw_writel(reg, IPU_SRM_PRI2);
    679 
    680 		timeout = 50;
    681 
    682 		/*
    683 		 * Wait for DC triple buffer to empty,
    684 		 * this check is useful for tv overlay.
    685 		 */
    686 		if (g_dc_di_assignment[dc_chan] == 0)
    687 			while ((__raw_readl(DC_STAT) & 0x00000002)
    688 			       != 0x00000002) {
    689 				udelay(2000);
    690 				timeout -= 2;
    691 				if (timeout <= 0)
    692 					break;
    693 			}
    694 		else if (g_dc_di_assignment[dc_chan] == 1)
    695 			while ((__raw_readl(DC_STAT) & 0x00000020)
    696 			       != 0x00000020) {
    697 				udelay(2000);
    698 				timeout -= 2;
    699 				if (timeout <= 0)
    700 					break;
    701 			}
    702 		return;
    703 	} else {
    704 		return;
    705 	}
    706 
    707 	if (dc_swap) {
    708 		/* Swap DC channel 1 and 5 settings, and disable old dc chan */
    709 		reg = __raw_readl(DC_WR_CH_CONF(dc_chan));
    710 		__raw_writel(reg, DC_WR_CH_CONF(6 - dc_chan));
    711 		reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
    712 		reg ^= DC_WR_CH_CONF_PROG_DI_ID;
    713 		__raw_writel(reg, DC_WR_CH_CONF(dc_chan));
    714 	} else {
    715 		/* Make sure that we leave at the irq starting edge */
    716 		__raw_writel(IPUIRQ_2_MASK(irq), IPUIRQ_2_STATREG(irq));
    717 		do {
    718 			reg = __raw_readl(IPUIRQ_2_STATREG(irq));
    719 		} while (!(reg & IPUIRQ_2_MASK(irq)));
    720 
    721 		reg = __raw_readl(DC_WR_CH_CONF(dc_chan));
    722 		reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
    723 		__raw_writel(reg, DC_WR_CH_CONF(dc_chan));
    724 
    725 		reg = __raw_readl(IPU_DISP_GEN);
    726 		if (g_dc_di_assignment[dc_chan])
    727 			reg &= ~DI1_COUNTER_RELEASE;
    728 		else
    729 			reg &= ~DI0_COUNTER_RELEASE;
    730 		__raw_writel(reg, IPU_DISP_GEN);
    731 
    732 		/* Clock is already off because it must be done quickly, but
    733 		   we need to fix the ref count */
    734 		clk_disable(g_pixel_clk[g_dc_di_assignment[dc_chan]]);
    735 	}
    736 }
    737 
    738 void ipu_init_dc_mappings(void)
    739 {
    740 	/* IPU_PIX_FMT_RGB24 */
    741 	ipu_dc_map_clear(0);
    742 	ipu_dc_map_config(0, 0, 7, 0xFF);
    743 	ipu_dc_map_config(0, 1, 15, 0xFF);
    744 	ipu_dc_map_config(0, 2, 23, 0xFF);
    745 
    746 	/* IPU_PIX_FMT_RGB666 */
    747 	ipu_dc_map_clear(1);
    748 	ipu_dc_map_config(1, 0, 5, 0xFC);
    749 	ipu_dc_map_config(1, 1, 11, 0xFC);
    750 	ipu_dc_map_config(1, 2, 17, 0xFC);
    751 
    752 	/* IPU_PIX_FMT_YUV444 */
    753 	ipu_dc_map_clear(2);
    754 	ipu_dc_map_config(2, 0, 15, 0xFF);
    755 	ipu_dc_map_config(2, 1, 23, 0xFF);
    756 	ipu_dc_map_config(2, 2, 7, 0xFF);
    757 
    758 	/* IPU_PIX_FMT_RGB565 */
    759 	ipu_dc_map_clear(3);
    760 	ipu_dc_map_config(3, 0, 4, 0xF8);
    761 	ipu_dc_map_config(3, 1, 10, 0xFC);
    762 	ipu_dc_map_config(3, 2, 15, 0xF8);
    763 
    764 	/* IPU_PIX_FMT_LVDS666 */
    765 	ipu_dc_map_clear(4);
    766 	ipu_dc_map_config(4, 0, 5, 0xFC);
    767 	ipu_dc_map_config(4, 1, 13, 0xFC);
    768 	ipu_dc_map_config(4, 2, 21, 0xFC);
    769 }
    770 
    771 static int ipu_pixfmt_to_map(uint32_t fmt)
    772 {
    773 	switch (fmt) {
    774 	case IPU_PIX_FMT_GENERIC:
    775 	case IPU_PIX_FMT_RGB24:
    776 		return 0;
    777 	case IPU_PIX_FMT_RGB666:
    778 		return 1;
    779 	case IPU_PIX_FMT_YUV444:
    780 		return 2;
    781 	case IPU_PIX_FMT_RGB565:
    782 		return 3;
    783 	case IPU_PIX_FMT_LVDS666:
    784 		return 4;
    785 	}
    786 
    787 	return -1;
    788 }
    789 
    790 /*
    791  * This function is called to initialize a synchronous LCD panel.
    792  *
    793  * @param       disp            The DI the panel is attached to.
    794  *
    795  * @param       pixel_clk       Desired pixel clock frequency in Hz.
    796  *
    797  * @param       pixel_fmt       Input parameter for pixel format of buffer.
    798  *                              Pixel format is a FOURCC ASCII code.
    799  *
    800  * @param       width           The width of panel in pixels.
    801  *
    802  * @param       height          The height of panel in pixels.
    803  *
    804  * @param       hStartWidth     The number of pixel clocks between the HSYNC
    805  *                              signal pulse and the start of valid data.
    806  *
    807  * @param       hSyncWidth      The width of the HSYNC signal in units of pixel
    808  *                              clocks.
    809  *
    810  * @param       hEndWidth       The number of pixel clocks between the end of
    811  *                              valid data and the HSYNC signal for next line.
    812  *
    813  * @param       vStartWidth     The number of lines between the VSYNC
    814  *                              signal pulse and the start of valid data.
    815  *
    816  * @param       vSyncWidth      The width of the VSYNC signal in units of lines
    817  *
    818  * @param       vEndWidth       The number of lines between the end of valid
    819  *                              data and the VSYNC signal for next frame.
    820  *
    821  * @param       sig             Bitfield of signal polarities for LCD interface.
    822  *
    823  * @return      This function returns 0 on success or negative error code on
    824  *              fail.
    825  */
    826 
    827 int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk,
    828 			    uint16_t width, uint16_t height,
    829 			    uint32_t pixel_fmt,
    830 			    uint16_t h_start_width, uint16_t h_sync_width,
    831 			    uint16_t h_end_width, uint16_t v_start_width,
    832 			    uint16_t v_sync_width, uint16_t v_end_width,
    833 			    uint32_t v_to_h_sync, ipu_di_signal_cfg_t sig)
    834 {
    835 	uint32_t reg;
    836 	uint32_t di_gen, vsync_cnt;
    837 	uint32_t div, rounded_pixel_clk;
    838 	uint32_t h_total, v_total;
    839 	int map;
    840 	struct clk *di_parent;
    841 
    842 	debug("panel size = %d x %d\n", width, height);
    843 
    844 	if ((v_sync_width == 0) || (h_sync_width == 0))
    845 		return -EINVAL;
    846 
    847 	/* adapt panel to ipu restricitions */
    848 	if (v_end_width < 2) {
    849 		v_end_width = 2;
    850 		puts("WARNING: v_end_width (lower_margin) must be >= 2, adjusted\n");
    851 	}
    852 
    853 	h_total = width + h_sync_width + h_start_width + h_end_width;
    854 	v_total = height + v_sync_width + v_start_width + v_end_width;
    855 
    856 	/* Init clocking */
    857 	debug("pixel clk = %dHz\n", pixel_clk);
    858 
    859 	if (sig.ext_clk) {
    860 		if (!(g_di1_tvout && (disp == 1))) { /*not round div for tvout*/
    861 			/*
    862 			 * Set the  PLL to be an even multiple
    863 			 * of the pixel clock.
    864 			 */
    865 			if ((clk_get_usecount(g_pixel_clk[0]) == 0) &&
    866 				(clk_get_usecount(g_pixel_clk[1]) == 0)) {
    867 				di_parent = clk_get_parent(g_di_clk[disp]);
    868 				rounded_pixel_clk =
    869 					clk_round_rate(g_pixel_clk[disp],
    870 						pixel_clk);
    871 				div  = clk_get_rate(di_parent) /
    872 					rounded_pixel_clk;
    873 				if (div % 2)
    874 					div++;
    875 				if (clk_get_rate(di_parent) != div *
    876 					rounded_pixel_clk)
    877 					clk_set_rate(di_parent,
    878 						div * rounded_pixel_clk);
    879 				udelay(10000);
    880 				clk_set_rate(g_di_clk[disp],
    881 					2 * rounded_pixel_clk);
    882 				udelay(10000);
    883 			}
    884 		}
    885 		clk_set_parent(g_pixel_clk[disp], g_ldb_clk);
    886 	} else {
    887 		if (clk_get_usecount(g_pixel_clk[disp]) != 0)
    888 			clk_set_parent(g_pixel_clk[disp], g_ipu_clk);
    889 	}
    890 	rounded_pixel_clk = clk_round_rate(g_pixel_clk[disp], pixel_clk);
    891 	clk_set_rate(g_pixel_clk[disp], rounded_pixel_clk);
    892 	udelay(5000);
    893 	/* Get integer portion of divider */
    894 	div = clk_get_rate(clk_get_parent(g_pixel_clk[disp])) /
    895 		rounded_pixel_clk;
    896 
    897 	ipu_di_data_wave_config(disp, SYNC_WAVE, div - 1, div - 1);
    898 	ipu_di_data_pin_config(disp, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
    899 
    900 	map = ipu_pixfmt_to_map(pixel_fmt);
    901 	if (map < 0) {
    902 		debug("IPU_DISP: No MAP\n");
    903 		return -EINVAL;
    904 	}
    905 
    906 	di_gen = __raw_readl(DI_GENERAL(disp));
    907 
    908 	if (sig.interlaced) {
    909 		/* Setup internal HSYNC waveform */
    910 		ipu_di_sync_config(
    911 				disp,		/* display */
    912 				1,		/* counter */
    913 				h_total / 2 - 1,/* run count */
    914 				DI_SYNC_CLK,	/* run_resolution */
    915 				0,		/* offset */
    916 				DI_SYNC_NONE,	/* offset resolution */
    917 				0,		/* repeat count */
    918 				DI_SYNC_NONE,	/* CNT_CLR_SEL */
    919 				0,		/* CNT_POLARITY_GEN_EN */
    920 				DI_SYNC_NONE,	/* CNT_POLARITY_CLR_SEL */
    921 				DI_SYNC_NONE,	/* CNT_POLARITY_TRIGGER_SEL */
    922 				0,		/* COUNT UP */
    923 				0		/* COUNT DOWN */
    924 				);
    925 
    926 		/* Field 1 VSYNC waveform */
    927 		ipu_di_sync_config(
    928 				disp,		/* display */
    929 				2,		/* counter */
    930 				h_total - 1,	/* run count */
    931 				DI_SYNC_CLK,	/* run_resolution */
    932 				0,		/* offset */
    933 				DI_SYNC_NONE,	/* offset resolution */
    934 				0,		/* repeat count */
    935 				DI_SYNC_NONE,	/* CNT_CLR_SEL */
    936 				0,		/* CNT_POLARITY_GEN_EN */
    937 				DI_SYNC_NONE,	/* CNT_POLARITY_CLR_SEL */
    938 				DI_SYNC_NONE,	/* CNT_POLARITY_TRIGGER_SEL */
    939 				0,		/* COUNT UP */
    940 				4		/* COUNT DOWN */
    941 				);
    942 
    943 		/* Setup internal HSYNC waveform */
    944 		ipu_di_sync_config(
    945 				disp,		/* display */
    946 				3,		/* counter */
    947 				v_total * 2 - 1,/* run count */
    948 				DI_SYNC_INT_HSYNC,	/* run_resolution */
    949 				1,		/* offset */
    950 				DI_SYNC_INT_HSYNC,	/* offset resolution */
    951 				0,		/* repeat count */
    952 				DI_SYNC_NONE,	/* CNT_CLR_SEL */
    953 				0,		/* CNT_POLARITY_GEN_EN */
    954 				DI_SYNC_NONE,	/* CNT_POLARITY_CLR_SEL */
    955 				DI_SYNC_NONE,	/* CNT_POLARITY_TRIGGER_SEL */
    956 				0,		/* COUNT UP */
    957 				4		/* COUNT DOWN */
    958 				);
    959 
    960 		/* Active Field ? */
    961 		ipu_di_sync_config(
    962 				disp,		/* display */
    963 				4,		/* counter */
    964 				v_total / 2 - 1,/* run count */
    965 				DI_SYNC_HSYNC,	/* run_resolution */
    966 				v_start_width,	/*  offset */
    967 				DI_SYNC_HSYNC,	/* offset resolution */
    968 				2,		/* repeat count */
    969 				DI_SYNC_VSYNC,	/* CNT_CLR_SEL */
    970 				0,		/* CNT_POLARITY_GEN_EN */
    971 				DI_SYNC_NONE,	/* CNT_POLARITY_CLR_SEL */
    972 				DI_SYNC_NONE,	/* CNT_POLARITY_TRIGGER_SEL */
    973 				0,		/* COUNT UP */
    974 				0		/* COUNT DOWN */
    975 				);
    976 
    977 		/* Active Line */
    978 		ipu_di_sync_config(
    979 				disp,		/* display */
    980 				5,		/* counter */
    981 				0,		/* run count */
    982 				DI_SYNC_HSYNC,	/* run_resolution */
    983 				0,		/*  offset */
    984 				DI_SYNC_NONE,	/* offset resolution */
    985 				height / 2,	/* repeat count */
    986 				4,		/* CNT_CLR_SEL */
    987 				0,		/* CNT_POLARITY_GEN_EN */
    988 				DI_SYNC_NONE,	/* CNT_POLARITY_CLR_SEL */
    989 				DI_SYNC_NONE,	/* CNT_POLARITY_TRIGGER_SEL */
    990 				0,		/* COUNT UP */
    991 				0		/* COUNT DOWN */
    992 				);
    993 
    994 		/* Field 0 VSYNC waveform */
    995 		ipu_di_sync_config(
    996 				disp,		/* display */
    997 				6,		/* counter */
    998 				v_total - 1,	/* run count */
    999 				DI_SYNC_HSYNC,	/* run_resolution */
   1000 				0,		/* offset */
   1001 				DI_SYNC_NONE,	/* offset resolution */
   1002 				0,		/* repeat count */
   1003 				DI_SYNC_NONE,	/* CNT_CLR_SEL  */
   1004 				0,		/* CNT_POLARITY_GEN_EN */
   1005 				DI_SYNC_NONE,	/* CNT_POLARITY_CLR_SEL */
   1006 				DI_SYNC_NONE,	/* CNT_POLARITY_TRIGGER_SEL */
   1007 				0,		/* COUNT UP */
   1008 				0		/* COUNT DOWN */
   1009 				);
   1010 
   1011 		/* DC VSYNC waveform */
   1012 		vsync_cnt = 7;
   1013 		ipu_di_sync_config(
   1014 				disp,		/* display */
   1015 				7,		/* counter */
   1016 				v_total / 2 - 1,/* run count */
   1017 				DI_SYNC_HSYNC,	/* run_resolution  */
   1018 				9,		/* offset  */
   1019 				DI_SYNC_HSYNC,	/* offset resolution */
   1020 				2,		/* repeat count */
   1021 				DI_SYNC_VSYNC,	/* CNT_CLR_SEL */
   1022 				0,		/* CNT_POLARITY_GEN_EN */
   1023 				DI_SYNC_NONE,	/* CNT_POLARITY_CLR_SEL */
   1024 				DI_SYNC_NONE,	/* CNT_POLARITY_TRIGGER_SEL */
   1025 				0,		/* COUNT UP */
   1026 				0		/* COUNT DOWN */
   1027 				);
   1028 
   1029 		/* active pixel waveform */
   1030 		ipu_di_sync_config(
   1031 				disp,		/* display */
   1032 				8,		/* counter */
   1033 				0,		/* run count  */
   1034 				DI_SYNC_CLK,	/* run_resolution */
   1035 				h_start_width,	/* offset  */
   1036 				DI_SYNC_CLK,	/* offset resolution */
   1037 				width,		/* repeat count  */
   1038 				5,		/* CNT_CLR_SEL  */
   1039 				0,		/* CNT_POLARITY_GEN_EN  */
   1040 				DI_SYNC_NONE,	/* CNT_POLARITY_CLR_SEL */
   1041 				DI_SYNC_NONE,	/* CNT_POLARITY_TRIGGER_SEL  */
   1042 				0,		/* COUNT UP  */
   1043 				0		/* COUNT DOWN */
   1044 				);
   1045 
   1046 		ipu_di_sync_config(
   1047 				disp,		/* display */
   1048 				9,		/* counter */
   1049 				v_total - 1,	/* run count */
   1050 				DI_SYNC_INT_HSYNC,/* run_resolution */
   1051 				v_total / 2,	/* offset  */
   1052 				DI_SYNC_INT_HSYNC,/* offset resolution  */
   1053 				0,		/* repeat count */
   1054 				DI_SYNC_HSYNC,	/* CNT_CLR_SEL */
   1055 				0,		/* CNT_POLARITY_GEN_EN  */
   1056 				DI_SYNC_NONE,	/* CNT_POLARITY_CLR_SEL  */
   1057 				DI_SYNC_NONE,	/* CNT_POLARITY_TRIGGER_SEL */
   1058 				0,		/* COUNT UP */
   1059 				4		/* COUNT DOWN */
   1060 				);
   1061 
   1062 		/* set gentime select and tag sel */
   1063 		reg = __raw_readl(DI_SW_GEN1(disp, 9));
   1064 		reg &= 0x1FFFFFFF;
   1065 		reg |= (3 - 1)<<29 | 0x00008000;
   1066 		__raw_writel(reg, DI_SW_GEN1(disp, 9));
   1067 
   1068 		__raw_writel(v_total / 2 - 1, DI_SCR_CONF(disp));
   1069 
   1070 		/* set y_sel = 1 */
   1071 		di_gen |= 0x10000000;
   1072 		di_gen |= DI_GEN_POLARITY_5;
   1073 		di_gen |= DI_GEN_POLARITY_8;
   1074 	} else {
   1075 		/* Setup internal HSYNC waveform */
   1076 		ipu_di_sync_config(disp, 1, h_total - 1, DI_SYNC_CLK,
   1077 				0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
   1078 				0, DI_SYNC_NONE,
   1079 				DI_SYNC_NONE, 0, 0);
   1080 
   1081 		/* Setup external (delayed) HSYNC waveform */
   1082 		ipu_di_sync_config(disp, DI_SYNC_HSYNC, h_total - 1,
   1083 				DI_SYNC_CLK, div * v_to_h_sync, DI_SYNC_CLK,
   1084 				0, DI_SYNC_NONE, 1, DI_SYNC_NONE,
   1085 				DI_SYNC_CLK, 0, h_sync_width * 2);
   1086 		/* Setup VSYNC waveform */
   1087 		vsync_cnt = DI_SYNC_VSYNC;
   1088 		ipu_di_sync_config(disp, DI_SYNC_VSYNC, v_total - 1,
   1089 				DI_SYNC_INT_HSYNC, 0, DI_SYNC_NONE, 0,
   1090 				DI_SYNC_NONE, 1, DI_SYNC_NONE,
   1091 				DI_SYNC_INT_HSYNC, 0, v_sync_width * 2);
   1092 		__raw_writel(v_total - 1, DI_SCR_CONF(disp));
   1093 
   1094 		/* Setup active data waveform to sync with DC */
   1095 		ipu_di_sync_config(disp, 4, 0, DI_SYNC_HSYNC,
   1096 				v_sync_width + v_start_width, DI_SYNC_HSYNC,
   1097 				height,
   1098 				DI_SYNC_VSYNC, 0, DI_SYNC_NONE,
   1099 				DI_SYNC_NONE, 0, 0);
   1100 		ipu_di_sync_config(disp, 5, 0, DI_SYNC_CLK,
   1101 				h_sync_width + h_start_width, DI_SYNC_CLK,
   1102 				width, 4, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0,
   1103 				0);
   1104 
   1105 		/* reset all unused counters */
   1106 		__raw_writel(0, DI_SW_GEN0(disp, 6));
   1107 		__raw_writel(0, DI_SW_GEN1(disp, 6));
   1108 		__raw_writel(0, DI_SW_GEN0(disp, 7));
   1109 		__raw_writel(0, DI_SW_GEN1(disp, 7));
   1110 		__raw_writel(0, DI_SW_GEN0(disp, 8));
   1111 		__raw_writel(0, DI_SW_GEN1(disp, 8));
   1112 		__raw_writel(0, DI_SW_GEN0(disp, 9));
   1113 		__raw_writel(0, DI_SW_GEN1(disp, 9));
   1114 
   1115 		reg = __raw_readl(DI_STP_REP(disp, 6));
   1116 		reg &= 0x0000FFFF;
   1117 		__raw_writel(reg, DI_STP_REP(disp, 6));
   1118 		__raw_writel(0, DI_STP_REP(disp, 7));
   1119 		__raw_writel(0, DI_STP_REP9(disp));
   1120 
   1121 		/* Init template microcode */
   1122 		if (disp) {
   1123 		   ipu_dc_write_tmpl(2, WROD(0), 0, map, SYNC_WAVE, 8, 5);
   1124 		   ipu_dc_write_tmpl(3, WROD(0), 0, map, SYNC_WAVE, 4, 5);
   1125 		   ipu_dc_write_tmpl(4, WROD(0), 0, map, SYNC_WAVE, 0, 5);
   1126 		} else {
   1127 		   ipu_dc_write_tmpl(5, WROD(0), 0, map, SYNC_WAVE, 8, 5);
   1128 		   ipu_dc_write_tmpl(6, WROD(0), 0, map, SYNC_WAVE, 4, 5);
   1129 		   ipu_dc_write_tmpl(7, WROD(0), 0, map, SYNC_WAVE, 0, 5);
   1130 		}
   1131 
   1132 		if (sig.Hsync_pol)
   1133 			di_gen |= DI_GEN_POLARITY_2;
   1134 		if (sig.Vsync_pol)
   1135 			di_gen |= DI_GEN_POLARITY_3;
   1136 
   1137 		if (!sig.clk_pol)
   1138 			di_gen |= DI_GEN_POL_CLK;
   1139 
   1140 	}
   1141 
   1142 	__raw_writel(di_gen, DI_GENERAL(disp));
   1143 
   1144 	__raw_writel((--vsync_cnt << DI_VSYNC_SEL_OFFSET) |
   1145 			0x00000002, DI_SYNC_AS_GEN(disp));
   1146 
   1147 	reg = __raw_readl(DI_POL(disp));
   1148 	reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
   1149 	if (sig.enable_pol)
   1150 		reg |= DI_POL_DRDY_POLARITY_15;
   1151 	if (sig.data_pol)
   1152 		reg |= DI_POL_DRDY_DATA_POLARITY;
   1153 	__raw_writel(reg, DI_POL(disp));
   1154 
   1155 	__raw_writel(width, DC_DISP_CONF2(DC_DISP_ID_SYNC(disp)));
   1156 
   1157 	return 0;
   1158 }
   1159 
   1160 /*
   1161  * This function sets the foreground and background plane global alpha blending
   1162  * modes. This function also sets the DP graphic plane according to the
   1163  * parameter of IPUv3 DP channel.
   1164  *
   1165  * @param	channel		IPUv3 DP channel
   1166  *
   1167  * @param       enable          Boolean to enable or disable global alpha
   1168  *                              blending. If disabled, local blending is used.
   1169  *
   1170  * @param       alpha           Global alpha value.
   1171  *
   1172  * @return      Returns 0 on success or negative error code on fail
   1173  */
   1174 int32_t ipu_disp_set_global_alpha(ipu_channel_t channel, unsigned char enable,
   1175 				  uint8_t alpha)
   1176 {
   1177 	uint32_t reg;
   1178 
   1179 	unsigned char bg_chan;
   1180 
   1181 	if (!((channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) ||
   1182 		(channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0) ||
   1183 		(channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1)))
   1184 		return -EINVAL;
   1185 
   1186 	if (channel == MEM_BG_SYNC || channel == MEM_BG_ASYNC0 ||
   1187 	    channel == MEM_BG_ASYNC1)
   1188 		bg_chan = 1;
   1189 	else
   1190 		bg_chan = 0;
   1191 
   1192 	if (!g_ipu_clk_enabled)
   1193 		clk_enable(g_ipu_clk);
   1194 
   1195 	if (bg_chan) {
   1196 		reg = __raw_readl(DP_COM_CONF());
   1197 		__raw_writel(reg & ~DP_COM_CONF_GWSEL, DP_COM_CONF());
   1198 	} else {
   1199 		reg = __raw_readl(DP_COM_CONF());
   1200 		__raw_writel(reg | DP_COM_CONF_GWSEL, DP_COM_CONF());
   1201 	}
   1202 
   1203 	if (enable) {
   1204 		reg = __raw_readl(DP_GRAPH_WIND_CTRL()) & 0x00FFFFFFL;
   1205 		__raw_writel(reg | ((uint32_t) alpha << 24),
   1206 			     DP_GRAPH_WIND_CTRL());
   1207 
   1208 		reg = __raw_readl(DP_COM_CONF());
   1209 		__raw_writel(reg | DP_COM_CONF_GWAM, DP_COM_CONF());
   1210 	} else {
   1211 		reg = __raw_readl(DP_COM_CONF());
   1212 		__raw_writel(reg & ~DP_COM_CONF_GWAM, DP_COM_CONF());
   1213 	}
   1214 
   1215 	reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
   1216 	__raw_writel(reg, IPU_SRM_PRI2);
   1217 
   1218 	if (!g_ipu_clk_enabled)
   1219 		clk_disable(g_ipu_clk);
   1220 
   1221 	return 0;
   1222 }
   1223 
   1224 /*
   1225  * This function sets the transparent color key for SDC graphic plane.
   1226  *
   1227  * @param       channel         Input parameter for the logical channel ID.
   1228  *
   1229  * @param       enable          Boolean to enable or disable color key
   1230  *
   1231  * @param       colorKey        24-bit RGB color for transparent color key.
   1232  *
   1233  * @return      Returns 0 on success or negative error code on fail
   1234  */
   1235 int32_t ipu_disp_set_color_key(ipu_channel_t channel, unsigned char enable,
   1236 			       uint32_t color_key)
   1237 {
   1238 	uint32_t reg;
   1239 	int y, u, v;
   1240 	int red, green, blue;
   1241 
   1242 	if (!((channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) ||
   1243 		(channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0) ||
   1244 		(channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1)))
   1245 		return -EINVAL;
   1246 
   1247 	if (!g_ipu_clk_enabled)
   1248 		clk_enable(g_ipu_clk);
   1249 
   1250 	color_key_4rgb = 1;
   1251 	/* Transform color key from rgb to yuv if CSC is enabled */
   1252 	if (((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) ||
   1253 		((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) ||
   1254 		((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) ||
   1255 		((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB))) {
   1256 
   1257 		debug("color key 0x%x need change to yuv fmt\n", color_key);
   1258 
   1259 		red = (color_key >> 16) & 0xFF;
   1260 		green = (color_key >> 8) & 0xFF;
   1261 		blue = color_key & 0xFF;
   1262 
   1263 		y = rgb_to_yuv(0, red, green, blue);
   1264 		u = rgb_to_yuv(1, red, green, blue);
   1265 		v = rgb_to_yuv(2, red, green, blue);
   1266 		color_key = (y << 16) | (u << 8) | v;
   1267 
   1268 		color_key_4rgb = 0;
   1269 
   1270 		debug("color key change to yuv fmt 0x%x\n", color_key);
   1271 	}
   1272 
   1273 	if (enable) {
   1274 		reg = __raw_readl(DP_GRAPH_WIND_CTRL()) & 0xFF000000L;
   1275 		__raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL());
   1276 
   1277 		reg = __raw_readl(DP_COM_CONF());
   1278 		__raw_writel(reg | DP_COM_CONF_GWCKE, DP_COM_CONF());
   1279 	} else {
   1280 		reg = __raw_readl(DP_COM_CONF());
   1281 		__raw_writel(reg & ~DP_COM_CONF_GWCKE, DP_COM_CONF());
   1282 	}
   1283 
   1284 	reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
   1285 	__raw_writel(reg, IPU_SRM_PRI2);
   1286 
   1287 	if (!g_ipu_clk_enabled)
   1288 		clk_disable(g_ipu_clk);
   1289 
   1290 	return 0;
   1291 }
   1292