ENGR00123439 DMFC size: IPU DMFC DP high resulution fail to display small frame
[efikamx:linux-kernel.git] / drivers / mxc / ipu3 / ipu_disp.c
1 /*
2  * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved.
3  */
4
5 /*
6  * The code contained herein is licensed under the GNU General Public
7  * License. You may obtain a copy of the GNU General Public License
8  * Version 2 or later at the following locations:
9  *
10  * http://www.opensource.org/licenses/gpl-license.html
11  * http://www.gnu.org/copyleft/gpl.html
12  */
13
14 /*!
15  * @file ipu_disp.c
16  *
17  * @brief IPU display submodule API functions
18  *
19  * @ingroup IPU
20  */
21 #include <linux/types.h>
22 #include <linux/errno.h>
23 #include <linux/delay.h>
24 #include <linux/spinlock.h>
25 #include <linux/io.h>
26 #include <linux/ipu.h>
27 #include <linux/clk.h>
28 #include <asm/atomic.h>
29 #include <mach/mxc_dvfs.h>
30 #include <mach/clock.h>
31 #include "ipu_prv.h"
32 #include "ipu_regs.h"
33 #include "ipu_param_mem.h"
34
35 enum csc_type_t {
36         RGB2YUV = 0,
37         YUV2RGB,
38         RGB2RGB,
39         YUV2YUV,
40         CSC_NONE,
41         CSC_NUM
42 };
43
44 struct dp_csc_param_t {
45         int mode;
46         void *coeff;
47 };
48
49 #define SYNC_WAVE 0
50 #define ASYNC_SER_WAVE 6
51
52 /* DC display ID assignments */
53 #define DC_DISP_ID_SYNC(di)     (di)
54 #define DC_DISP_ID_SERIAL       2
55 #define DC_DISP_ID_ASYNC        3
56
57 int dmfc_type_setup;
58 static int dmfc_size_28, dmfc_size_29, dmfc_size_24, dmfc_size_27, dmfc_size_23;
59
60 void _ipu_dmfc_init(int dmfc_type, int first)
61 {
62         u32 dmfc_wr_chan, dmfc_dp_chan;
63
64         if (first) {
65                 if (dmfc_type_setup > dmfc_type)
66                         dmfc_type = dmfc_type_setup;
67                 else
68                         dmfc_type_setup = dmfc_type;
69
70                 /* disable DMFC-IC channel*/
71                 __raw_writel(0x2, DMFC_IC_CTRL);
72         } else if (dmfc_type_setup >= DMFC_HIGH_RESOLUTION_DC) {
73                 printk(KERN_DEBUG "DMFC high resolution has set, will not change\n");
74                 return;
75         } else
76                 dmfc_type_setup = dmfc_type;
77
78         if (dmfc_type == DMFC_HIGH_RESOLUTION_DC) {
79                 /* 1 - segment 0~3;
80                  * 5B - segement 4, 5;
81                  * 5F - segement 6, 7;
82                  * 1C, 2C and 6B, 6F unused;
83                  */
84                 printk(KERN_INFO "IPU DMFC DC HIGH RESOLUTION: 1(0~3), 5B(4,5), 5F(6,7)\n");
85                 dmfc_wr_chan = 0x00000088;
86                 dmfc_dp_chan = 0x00009694;
87                 dmfc_size_28 = 256*4;
88                 dmfc_size_29 = 0;
89                 dmfc_size_24 = 0;
90                 dmfc_size_27 = 128*4;
91                 dmfc_size_23 = 128*4;
92         } else if (dmfc_type == DMFC_HIGH_RESOLUTION_DP) {
93                 /* 1 - segment 0, 1;
94                  * 5B - segement 2~5;
95                  * 5F - segement 6,7;
96                  * 1C, 2C and 6B, 6F unused;
97                  */
98                 printk(KERN_INFO "IPU DMFC DP HIGH RESOLUTION: 1(0,1), 5B(2~5), 5F(6,7)\n");
99                 dmfc_wr_chan = 0x00000090;
100                 dmfc_dp_chan = 0x0000968a;
101                 dmfc_size_28 = 128*4;
102                 dmfc_size_29 = 0;
103                 dmfc_size_24 = 0;
104                 dmfc_size_27 = 128*4;
105                 dmfc_size_23 = 256*4;
106         } else if (dmfc_type == DMFC_HIGH_RESOLUTION_ONLY_DP) {
107                 /* 5B - segement 0~3;
108                  * 5F - segement 4~7;
109                  * 1, 1C, 2C and 6B, 6F unused;
110                  */
111                 printk(KERN_INFO "IPU DMFC ONLY-DP HIGH RESOLUTION: 5B(0~3), 5F(4~7)\n");
112                 dmfc_wr_chan = 0x00000000;
113                 dmfc_dp_chan = 0x00008c88;
114                 dmfc_size_28 = 0;
115                 dmfc_size_29 = 0;
116                 dmfc_size_24 = 0;
117                 dmfc_size_27 = 256*4;
118                 dmfc_size_23 = 256*4;
119         } else {
120                 /* 1 - segment 0, 1;
121                  * 5B - segement 4, 5;
122                  * 5F - segement 6, 7;
123                  * 1C, 2C and 6B, 6F unused;
124                  */
125                 printk(KERN_INFO "IPU DMFC NORMAL mode: 1(0~1), 5B(4,5), 5F(6,7)\n");
126                 dmfc_wr_chan = 0x00000090;
127                 dmfc_dp_chan = 0x00009694;
128                 dmfc_size_28 = 128*4;
129                 dmfc_size_29 = 0;
130                 dmfc_size_24 = 0;
131                 dmfc_size_27 = 128*4;
132                 dmfc_size_23 = 128*4;
133         }
134         __raw_writel(dmfc_wr_chan, DMFC_WR_CHAN);
135         __raw_writel(0x202020F6, DMFC_WR_CHAN_DEF);
136         __raw_writel(dmfc_dp_chan, DMFC_DP_CHAN);
137         /* Enable chan 5 watermark set at 5 bursts and clear at 7 bursts */
138         __raw_writel(0x2020F6F6, DMFC_DP_CHAN_DEF);
139 }
140
141 static int __init dmfc_setup(char *options)
142 {
143         get_option(&options, &dmfc_type_setup);
144         if (dmfc_type_setup > DMFC_HIGH_RESOLUTION_ONLY_DP)
145                 dmfc_type_setup = DMFC_HIGH_RESOLUTION_ONLY_DP;
146         return 1;
147 }
148 __setup("dmfc=", dmfc_setup);
149
150 static bool _ipu_update_dmfc_used_size(int dma_chan, int width, int dmfc_size)
151 {
152         u32 fifo_size_5f = 1;
153         u32 dmfc_dp_chan = __raw_readl(DMFC_DP_CHAN);
154
155         if ((width > 352) && (dmfc_size == (256 * 4)))
156                 fifo_size_5f = 1;
157         else if (width > 176)
158                 fifo_size_5f = 2;
159         else if (width > 88)
160                 fifo_size_5f = 3;
161         else if (width > 44)
162                 fifo_size_5f = 4;
163         else if (width > 22)
164                 fifo_size_5f = 5;
165         else if (width > 11)
166                 fifo_size_5f = 6;
167         else if (width > 6)
168                 fifo_size_5f = 7;
169         else
170                 return false;
171
172         if (dma_chan == 27) {
173                 dmfc_dp_chan &= ~DMFC_FIFO_SIZE_5F;
174                 dmfc_dp_chan |= fifo_size_5f << 11;
175                 __raw_writel(dmfc_dp_chan, DMFC_DP_CHAN);
176         }
177
178         return true;
179 }
180
181 void _ipu_dmfc_set_wait4eot(int dma_chan, int width)
182 {
183         u32 dmfc_gen1 = __raw_readl(DMFC_GENERAL1);
184
185         if (width >= HIGH_RESOLUTION_WIDTH) {
186                 if (dma_chan == 23)
187                         _ipu_dmfc_init(DMFC_HIGH_RESOLUTION_DP, 0);
188                 else if (dma_chan == 28)
189                         _ipu_dmfc_init(DMFC_HIGH_RESOLUTION_DC, 0);
190         }
191
192         if (dma_chan == 23) { /*5B*/
193                 if (dmfc_size_23/width > 3)
194                         dmfc_gen1 |= 1UL << 20;
195                 else
196                         dmfc_gen1 &= ~(1UL << 20);
197         } else if (dma_chan == 24) { /*6B*/
198                 if (dmfc_size_24/width > 1)
199                         dmfc_gen1 |= 1UL << 22;
200                 else
201                         dmfc_gen1 &= ~(1UL << 22);
202         } else if (dma_chan == 27) { /*5F*/
203                 if (!_ipu_update_dmfc_used_size(dma_chan, width, dmfc_size_27))
204                         dmfc_gen1 |= 1UL << 21;
205                 else
206                         dmfc_gen1 &= ~(1UL << 21);
207         } else if (dma_chan == 28) { /*1*/
208                 if (dmfc_size_28/width > 2)
209                         dmfc_gen1 |= 1UL << 16;
210                 else
211                         dmfc_gen1 &= ~(1UL << 16);
212         } else if (dma_chan == 29) { /*6F*/
213                 if (dmfc_size_29/width > 1)
214                         dmfc_gen1 |= 1UL << 23;
215                 else
216                         dmfc_gen1 &= ~(1UL << 23);
217         }
218
219         __raw_writel(dmfc_gen1, DMFC_GENERAL1);
220 }
221
222 static void _ipu_di_data_wave_config(int di,
223                                      int wave_gen,
224                                      int access_size, int component_size)
225 {
226         u32 reg;
227         reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
228             (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
229         __raw_writel(reg, DI_DW_GEN(di, wave_gen));
230 }
231
232 static void _ipu_di_data_pin_config(int di, int wave_gen, int di_pin, int set,
233                                     int up, int down)
234 {
235         u32 reg;
236
237         reg = __raw_readl(DI_DW_GEN(di, wave_gen));
238         reg &= ~(0x3 << (di_pin * 2));
239         reg |= set << (di_pin * 2);
240         __raw_writel(reg, DI_DW_GEN(di, wave_gen));
241
242         __raw_writel((down << 16) | up, DI_DW_SET(di, wave_gen, set));
243 }
244
245 static void _ipu_di_sync_config(int di, int wave_gen,
246                                 int run_count, int run_src,
247                                 int offset_count, int offset_src,
248                                 int repeat_count, int cnt_clr_src,
249                                 int cnt_polarity_gen_en,
250                                 int cnt_polarity_clr_src,
251                                 int cnt_polarity_trigger_src,
252                                 int cnt_up, int cnt_down)
253 {
254         u32 reg;
255
256         if ((run_count >= 0x1000) || (offset_count >= 0x1000) || (repeat_count >= 0x1000) ||
257                 (cnt_up >= 0x400) || (cnt_down >= 0x400)) {
258                 dev_err(g_ipu_dev, "DI%d counters out of range.\n", di);
259                 return;
260         }
261
262         reg = (run_count << 19) | (++run_src << 16) |
263             (offset_count << 3) | ++offset_src;
264         __raw_writel(reg, DI_SW_GEN0(di, wave_gen));
265         reg = (cnt_polarity_gen_en << 29) | (++cnt_clr_src << 25) |
266             (++cnt_polarity_trigger_src << 12) | (++cnt_polarity_clr_src << 9);
267         reg |= (cnt_down << 16) | cnt_up;
268         if (repeat_count == 0) {
269                 /* Enable auto reload */
270                 reg |= 0x10000000;
271         }
272         __raw_writel(reg, DI_SW_GEN1(di, wave_gen));
273         reg = __raw_readl(DI_STP_REP(di, wave_gen));
274         reg &= ~(0xFFFF << (16 * ((wave_gen - 1) & 0x1)));
275         reg |= repeat_count << (16 * ((wave_gen - 1) & 0x1));
276         __raw_writel(reg, DI_STP_REP(di, wave_gen));
277 }
278
279 static void _ipu_dc_map_config(int map, int byte_num, int offset, int mask)
280 {
281         int ptr = map * 3 + byte_num;
282         u32 reg;
283
284         reg = __raw_readl(DC_MAP_CONF_VAL(ptr));
285         reg &= ~(0xFFFF << (16 * (ptr & 0x1)));
286         reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
287         __raw_writel(reg, DC_MAP_CONF_VAL(ptr));
288
289         reg = __raw_readl(DC_MAP_CONF_PTR(map));
290         reg &= ~(0x1F << ((16 * (map & 0x1)) + (5 * byte_num)));
291         reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
292         __raw_writel(reg, DC_MAP_CONF_PTR(map));
293 }
294
295 static void _ipu_dc_map_clear(int map)
296 {
297         u32 reg = __raw_readl(DC_MAP_CONF_PTR(map));
298         __raw_writel(reg & ~(0xFFFF << (16 * (map & 0x1))),
299                      DC_MAP_CONF_PTR(map));
300 }
301
302 static void _ipu_dc_write_tmpl(int word, u32 opcode, u32 operand, int map,
303                                int wave, int glue, int sync)
304 {
305         u32 reg;
306         int stop = 1;
307
308         reg = sync;
309         reg |= (glue << 4);
310         reg |= (++wave << 11);
311         reg |= (++map << 15);
312         reg |= (operand << 20) & 0xFFF00000;
313         __raw_writel(reg, ipu_dc_tmpl_reg + word * 2);
314
315         reg = (operand >> 12);
316         reg |= opcode << 4;
317         reg |= (stop << 9);
318         __raw_writel(reg, ipu_dc_tmpl_reg + word * 2 + 1);
319 }
320
321 static void _ipu_dc_link_event(int chan, int event, int addr, int priority)
322 {
323         u32 reg;
324
325         reg = __raw_readl(DC_RL_CH(chan, event));
326         reg &= ~(0xFFFF << (16 * (event & 0x1)));
327         reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
328         __raw_writel(reg, DC_RL_CH(chan, event));
329 }
330
331 /*     Y = R *  1.200 + G *  2.343 + B *  .453 + 0.250;
332        U = R * -.672 + G * -1.328 + B *  2.000 + 512.250.;
333        V = R *  2.000 + G * -1.672 + B * -.328 + 512.250.;*/
334 static const int rgb2ycbcr_coeff[5][3] = {
335         {0x4D, 0x96, 0x1D},
336         {-0x2B, -0x55, 0x80},
337         {0x80, -0x6B, -0x15},
338         {0x0000, 0x0200, 0x0200},       /* B0, B1, B2 */
339         {0x2, 0x2, 0x2},        /* S0, S1, S2 */
340 };
341
342 /*     R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
343        G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
344        B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); */
345 static const int ycbcr2rgb_coeff[5][3] = {
346         {0x095, 0x000, 0x0CC},
347         {0x095, 0x3CE, 0x398},
348         {0x095, 0x0FF, 0x000},
349         {0x3E42, 0x010A, 0x3DD6},       /*B0,B1,B2 */
350         {0x1, 0x1, 0x1},        /*S0,S1,S2 */
351 };
352
353 #define mask_a(a) ((u32)(a) & 0x3FF)
354 #define mask_b(b) ((u32)(b) & 0x3FFF)
355
356 /* Pls keep S0, S1 and S2 as 0x2 by using this convertion */
357 static int _rgb_to_yuv(int n, int red, int green, int blue)
358 {
359         int c;
360         c = red * rgb2ycbcr_coeff[n][0];
361         c += green * rgb2ycbcr_coeff[n][1];
362         c += blue * rgb2ycbcr_coeff[n][2];
363         c /= 16;
364         c += rgb2ycbcr_coeff[3][n] * 4;
365         c += 8;
366         c /= 16;
367         if (c < 0)
368                 c = 0;
369         if (c > 255)
370                 c = 255;
371         return c;
372 }
373
374 /*
375  * Row is for BG:       RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
376  * Column is for FG:    RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
377  */
378 static struct dp_csc_param_t dp_csc_array[CSC_NUM][CSC_NUM] = {
379 {{DP_COM_CONF_CSC_DEF_BOTH, &rgb2ycbcr_coeff}, {0, 0}, {0, 0}, {DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff}, {DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff} },
380 {{0, 0}, {DP_COM_CONF_CSC_DEF_BOTH, &ycbcr2rgb_coeff}, {DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff}, {0, 0}, {DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff} },
381 {{0, 0}, {DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff}, {0, 0}, {0, 0}, {0, 0} },
382 {{DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff}, {0, 0}, {0, 0}, {0, 0}, {0, 0} },
383 {{DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff}, {DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff}, {0, 0}, {0, 0}, {0, 0} }
384 };
385
386 static enum csc_type_t fg_csc_type = CSC_NONE, bg_csc_type = CSC_NONE;
387 static int color_key_4rgb = 1;
388
389 void __ipu_dp_csc_setup(int dp, struct dp_csc_param_t dp_csc_param,
390                         bool srm_mode_update)
391 {
392         u32 reg;
393         const int (*coeff)[5][3];
394
395         if (dp_csc_param.mode >= 0) {
396                 reg = __raw_readl(DP_COM_CONF(dp));
397                 reg &= ~DP_COM_CONF_CSC_DEF_MASK;
398                 reg |= dp_csc_param.mode;
399                 __raw_writel(reg, DP_COM_CONF(dp));
400         }
401
402         coeff = dp_csc_param.coeff;
403
404         if (coeff) {
405                 __raw_writel(mask_a((*coeff)[0][0]) |
406                                 (mask_a((*coeff)[0][1]) << 16), DP_CSC_A_0(dp));
407                 __raw_writel(mask_a((*coeff)[0][2]) |
408                                 (mask_a((*coeff)[1][0]) << 16), DP_CSC_A_1(dp));
409                 __raw_writel(mask_a((*coeff)[1][1]) |
410                                 (mask_a((*coeff)[1][2]) << 16), DP_CSC_A_2(dp));
411                 __raw_writel(mask_a((*coeff)[2][0]) |
412                                 (mask_a((*coeff)[2][1]) << 16), DP_CSC_A_3(dp));
413                 __raw_writel(mask_a((*coeff)[2][2]) |
414                                 (mask_b((*coeff)[3][0]) << 16) |
415                                 ((*coeff)[4][0] << 30), DP_CSC_0(dp));
416                 __raw_writel(mask_b((*coeff)[3][1]) | ((*coeff)[4][1] << 14) |
417                                 (mask_b((*coeff)[3][2]) << 16) |
418                                 ((*coeff)[4][2] << 30), DP_CSC_1(dp));
419         }
420
421         if (srm_mode_update) {
422                 reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
423                 __raw_writel(reg, IPU_SRM_PRI2);
424         }
425 }
426
427 int _ipu_dp_init(ipu_channel_t channel, uint32_t in_pixel_fmt,
428                  uint32_t out_pixel_fmt)
429 {
430         int in_fmt, out_fmt;
431         int dp;
432         int partial = false;
433         uint32_t reg;
434
435         if (channel == MEM_FG_SYNC) {
436                 dp = DP_SYNC;
437                 partial = true;
438         } else if (channel == MEM_BG_SYNC) {
439                 dp = DP_SYNC;
440                 partial = false;
441         } else if (channel == MEM_BG_ASYNC0) {
442                 dp = DP_ASYNC0;
443                 partial = false;
444         } else {
445                 return -EINVAL;
446         }
447
448         in_fmt = format_to_colorspace(in_pixel_fmt);
449         out_fmt = format_to_colorspace(out_pixel_fmt);
450
451         if (partial) {
452                 if (in_fmt == RGB) {
453                         if (out_fmt == RGB)
454                                 fg_csc_type = RGB2RGB;
455                         else
456                                 fg_csc_type = RGB2YUV;
457                 } else {
458                         if (out_fmt == RGB)
459                                 fg_csc_type = YUV2RGB;
460                         else
461                                 fg_csc_type = YUV2YUV;
462                 }
463         } else {
464                 if (in_fmt == RGB) {
465                         if (out_fmt == RGB)
466                                 bg_csc_type = RGB2RGB;
467                         else
468                                 bg_csc_type = RGB2YUV;
469                 } else {
470                         if (out_fmt == RGB)
471                                 bg_csc_type = YUV2RGB;
472                         else
473                                 bg_csc_type = YUV2YUV;
474                 }
475         }
476
477         /* Transform color key from rgb to yuv if CSC is enabled */
478         reg = __raw_readl(DP_COM_CONF(dp));
479         if (color_key_4rgb && (reg & DP_COM_CONF_GWCKE) &&
480                         (((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) ||
481                          ((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) ||
482                          ((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) ||
483                          ((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB)))) {
484                 int red, green, blue;
485                 int y, u, v;
486                 uint32_t color_key = __raw_readl(DP_GRAPH_WIND_CTRL(dp)) & 0xFFFFFFL;
487
488                 dev_dbg(g_ipu_dev, "_ipu_dp_init color key 0x%x need change to yuv fmt!\n", color_key);
489
490                 red = (color_key >> 16) & 0xFF;
491                 green = (color_key >> 8) & 0xFF;
492                 blue = color_key & 0xFF;
493
494                 y = _rgb_to_yuv(0, red, green, blue);
495                 u = _rgb_to_yuv(1, red, green, blue);
496                 v = _rgb_to_yuv(2, red, green, blue);
497                 color_key = (y << 16) | (u << 8) | v;
498
499                 reg = __raw_readl(DP_GRAPH_WIND_CTRL(dp)) & 0xFF000000L;
500                 __raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL(dp));
501                 color_key_4rgb = 0;
502
503                 dev_dbg(g_ipu_dev, "_ipu_dp_init color key change to yuv fmt 0x%x!\n", color_key);
504         }
505
506         __ipu_dp_csc_setup(dp, dp_csc_array[bg_csc_type][fg_csc_type], true);
507
508         return 0;
509 }
510
511 void _ipu_dp_uninit(ipu_channel_t channel)
512 {
513         int dp;
514         int partial = false;
515
516         if (channel == MEM_FG_SYNC) {
517                 dp = DP_SYNC;
518                 partial = true;
519         } else if (channel == MEM_BG_SYNC) {
520                 dp = DP_SYNC;
521                 partial = false;
522         } else if (channel == MEM_BG_ASYNC0) {
523                 dp = DP_ASYNC0;
524                 partial = false;
525         } else {
526                 return;
527         }
528
529         if (partial)
530                 fg_csc_type = CSC_NONE;
531         else
532                 bg_csc_type = CSC_NONE;
533
534         __ipu_dp_csc_setup(dp, dp_csc_array[bg_csc_type][fg_csc_type], false);
535 }
536
537 void _ipu_dc_init(int dc_chan, int di, bool interlaced)
538 {
539         u32 reg = 0;
540
541         if ((dc_chan == 1) || (dc_chan == 5)) {
542                 if (interlaced) {
543                         _ipu_dc_link_event(dc_chan, DC_EVT_NL, 0, 3);
544                         _ipu_dc_link_event(dc_chan, DC_EVT_EOL, 0, 2);
545                         _ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 0, 1);
546                 } else {
547                         if (di) {
548                                 _ipu_dc_link_event(dc_chan, DC_EVT_NL, 2, 3);
549                                 _ipu_dc_link_event(dc_chan, DC_EVT_EOL, 3, 2);
550                                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 4, 1);
551                         } else {
552                                 _ipu_dc_link_event(dc_chan, DC_EVT_NL, 5, 3);
553                                 _ipu_dc_link_event(dc_chan, DC_EVT_EOL, 6, 2);
554                                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 7, 1);
555                         }
556                 }
557                 _ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0);
558                 _ipu_dc_link_event(dc_chan, DC_EVT_NFIELD, 0, 0);
559                 _ipu_dc_link_event(dc_chan, DC_EVT_EOF, 0, 0);
560                 _ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0);
561                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0);
562                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0);
563
564                 reg = 0x2;
565                 reg |= DC_DISP_ID_SYNC(di) << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
566                 reg |= di << 2;
567                 if (interlaced)
568                         reg |= DC_WR_CH_CONF_FIELD_MODE;
569         } else if ((dc_chan == 8) || (dc_chan == 9)) {
570                 /* async channels */
571                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_0, 0x64, 1);
572                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_1, 0x64, 1);
573
574                 reg = 0x3;
575                 reg |= DC_DISP_ID_SERIAL << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
576         }
577         __raw_writel(reg, DC_WR_CH_CONF(dc_chan));
578
579         __raw_writel(0x00000000, DC_WR_CH_ADDR(dc_chan));
580
581         __raw_writel(0x00000084, DC_GEN);
582 }
583
584 void _ipu_dc_uninit(int dc_chan)
585 {
586         if ((dc_chan == 1) || (dc_chan == 5)) {
587                 _ipu_dc_link_event(dc_chan, DC_EVT_NL, 0, 0);
588                 _ipu_dc_link_event(dc_chan, DC_EVT_EOL, 0, 0);
589                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 0, 0);
590                 _ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0);
591                 _ipu_dc_link_event(dc_chan, DC_EVT_NFIELD, 0, 0);
592                 _ipu_dc_link_event(dc_chan, DC_EVT_EOF, 0, 0);
593                 _ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0);
594                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0);
595                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0);
596         } else if ((dc_chan == 8) || (dc_chan == 9)) {
597                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_0, 0, 0);
598                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_1, 0, 0);
599                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_W_0, 0, 0);
600                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_W_1, 0, 0);
601                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_0, 0, 0);
602                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_1, 0, 0);
603                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_R_0, 0, 0);
604                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_R_1, 0, 0);
605                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_R_0, 0, 0);
606                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_R_1, 0, 0);
607                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_R_0, 0, 0);
608                 _ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_R_1, 0, 0);
609         }
610 }
611
612 int _ipu_chan_is_interlaced(ipu_channel_t channel)
613 {
614         if (channel == MEM_DC_SYNC)
615                 return !!(__raw_readl(DC_WR_CH_CONF_1) &
616                           DC_WR_CH_CONF_FIELD_MODE);
617         else if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC))
618                 return !!(__raw_readl(DC_WR_CH_CONF_5) &
619                           DC_WR_CH_CONF_FIELD_MODE);
620         return 0;
621 }
622
623 void _ipu_dp_dc_enable(ipu_channel_t channel)
624 {
625         int di;
626         uint32_t reg;
627         uint32_t dc_chan;
628         int irq = 0;
629
630         if (channel == MEM_FG_SYNC)
631                 irq = IPU_IRQ_DP_SF_END;
632         else if (channel == MEM_DC_SYNC)
633                 dc_chan = 1;
634         else if (channel == MEM_BG_SYNC)
635                 dc_chan = 5;
636         else
637                 return;
638
639         if (channel == MEM_FG_SYNC) {
640                 /* Enable FG channel */
641                 reg = __raw_readl(DP_COM_CONF(DP_SYNC));
642                 __raw_writel(reg | DP_COM_CONF_FG_EN, DP_COM_CONF(DP_SYNC));
643
644                 reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
645                 __raw_writel(reg, IPU_SRM_PRI2);
646                 return;
647         }
648
649         di = g_dc_di_assignment[dc_chan];
650
651         /* Make sure other DC sync channel is not assigned same DI */
652         reg = __raw_readl(DC_WR_CH_CONF(6 - dc_chan));
653         if ((di << 2) == (reg & DC_WR_CH_CONF_PROG_DI_ID)) {
654                 reg &= ~DC_WR_CH_CONF_PROG_DI_ID;
655                 reg |= di ? 0 : DC_WR_CH_CONF_PROG_DI_ID;
656                 __raw_writel(reg, DC_WR_CH_CONF(6 - dc_chan));
657         }
658
659         reg = __raw_readl(DC_WR_CH_CONF(dc_chan));
660         reg |= 4 << DC_WR_CH_CONF_PROG_TYPE_OFFSET;
661         __raw_writel(reg, DC_WR_CH_CONF(dc_chan));
662
663         clk_enable(g_pixel_clk[di]);
664 }
665
666 static bool dc_swap;
667
668 static irqreturn_t dc_irq_handler(int irq, void *dev_id)
669 {
670         struct completion *comp = dev_id;
671
672         complete(comp);
673         return IRQ_HANDLED;
674 }
675
676 void _ipu_dp_dc_disable(ipu_channel_t channel, bool swap)
677 {
678         int ret;
679         unsigned long lock_flags;
680         uint32_t reg;
681         uint32_t csc;
682         uint32_t dc_chan;
683         int irq = 0;
684         int timeout = 50;
685         DECLARE_COMPLETION_ONSTACK(dc_comp);
686
687         dc_swap = swap;
688
689         if (channel == MEM_DC_SYNC) {
690                 dc_chan = 1;
691                 irq = IPU_IRQ_DC_FC_1;
692         } else if (channel == MEM_BG_SYNC) {
693                 dc_chan = 5;
694                 irq = IPU_IRQ_DP_SF_END;
695         } else if (channel == MEM_FG_SYNC) {
696                 /* Disable FG channel */
697                 dc_chan = 5;
698
699                 spin_lock_irqsave(&ipu_lock, lock_flags);
700
701                 reg = __raw_readl(DP_COM_CONF(DP_SYNC));
702                 csc = reg & DP_COM_CONF_CSC_DEF_MASK;
703                 if (csc == DP_COM_CONF_CSC_DEF_FG)
704                         reg &= ~DP_COM_CONF_CSC_DEF_MASK;
705
706                 reg &= ~DP_COM_CONF_FG_EN;
707                 __raw_writel(reg, DP_COM_CONF(DP_SYNC));
708
709                 reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
710                 __raw_writel(reg, IPU_SRM_PRI2);
711
712                 spin_unlock_irqrestore(&ipu_lock, lock_flags);
713
714                 __raw_writel(IPUIRQ_2_MASK(IPU_IRQ_DP_SF_END),
715                              IPUIRQ_2_STATREG(IPU_IRQ_DP_SF_END));
716                 while ((__raw_readl(IPUIRQ_2_STATREG(IPU_IRQ_DP_SF_END)) &
717                         IPUIRQ_2_MASK(IPU_IRQ_DP_SF_END)) == 0) {
718                         msleep(2);
719                         timeout -= 2;
720                         if (timeout <= 0)
721                                 break;
722                 }
723
724                 timeout = 50;
725
726                 /*
727                  * Wait for DC triple buffer to empty,
728                  * this check is useful for tv overlay.
729                  */
730                 if (g_dc_di_assignment[dc_chan] == 0)
731                         while ((__raw_readl(DC_STAT) & 0x00000002)
732                                != 0x00000002) {
733                                 msleep(2);
734                                 timeout -= 2;
735                                 if (timeout <= 0)
736                                         break;
737                         }
738                 else if (g_dc_di_assignment[dc_chan] == 1)
739                         while ((__raw_readl(DC_STAT) & 0x00000020)
740                                != 0x00000020) {
741                                 msleep(2);
742                                 timeout -= 2;
743                                 if (timeout <= 0)
744                                         break;
745                         }
746                 return;
747         } else {
748                 return;
749         }
750
751         if (!dc_swap)
752                 __raw_writel(IPUIRQ_2_MASK(IPU_IRQ_VSYNC_PRE_0
753                         + g_dc_di_assignment[dc_chan]),
754                      IPUIRQ_2_STATREG(IPU_IRQ_VSYNC_PRE_0
755                         + g_dc_di_assignment[dc_chan]));
756         ipu_clear_irq(irq);
757         ret = ipu_request_irq(irq, dc_irq_handler, 0, NULL, &dc_comp);
758         if (ret < 0) {
759                 dev_err(g_ipu_dev, "DC irq %d in use\n", irq);
760                 return;
761         }
762         ret = wait_for_completion_timeout(&dc_comp, msecs_to_jiffies(50));
763
764         dev_dbg(g_ipu_dev, "DC stop timeout - %d * 10ms\n", 5 - ret);
765         ipu_free_irq(irq, &dc_comp);
766
767         if (dc_swap) {
768                 spin_lock_irqsave(&ipu_lock, lock_flags);
769                 /* Swap DC channel 1 and 5 settings, and disable old dc chan */
770                 reg = __raw_readl(DC_WR_CH_CONF(dc_chan));
771                 __raw_writel(reg, DC_WR_CH_CONF(6 - dc_chan));
772                 reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
773                 reg ^= DC_WR_CH_CONF_PROG_DI_ID;
774                 __raw_writel(reg, DC_WR_CH_CONF(dc_chan));
775                 spin_unlock_irqrestore(&ipu_lock, lock_flags);
776         } else {
777                 timeout = 50;
778
779                 /* Wait for DC triple buffer to empty */
780                 if (g_dc_di_assignment[dc_chan] == 0)
781                         while ((__raw_readl(DC_STAT) & 0x00000002)
782                                 != 0x00000002) {
783                                 msleep(2);
784                                 timeout -= 2;
785                                 if (timeout <= 0)
786                                         break;
787                         }
788                 else if (g_dc_di_assignment[dc_chan] == 1)
789                         while ((__raw_readl(DC_STAT) & 0x00000020)
790                                 != 0x00000020) {
791                                 msleep(2);
792                                 timeout -= 2;
793                                 if (timeout <= 0)
794                                         break;
795                         }
796
797                 spin_lock_irqsave(&ipu_lock, lock_flags);
798                 reg = __raw_readl(DC_WR_CH_CONF(dc_chan));
799                 reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
800                 __raw_writel(reg, DC_WR_CH_CONF(dc_chan));
801
802                 reg = __raw_readl(IPU_DISP_GEN);
803                 if (g_dc_di_assignment[dc_chan])
804                         reg &= ~DI1_COUNTER_RELEASE;
805                 else
806                         reg &= ~DI0_COUNTER_RELEASE;
807                 __raw_writel(reg, IPU_DISP_GEN);
808
809                 spin_unlock_irqrestore(&ipu_lock, lock_flags);
810                 /* Clock is already off because it must be done quickly, but
811                    we need to fix the ref count */
812                 clk_disable(g_pixel_clk[g_dc_di_assignment[dc_chan]]);
813
814                 if (__raw_readl(IPUIRQ_2_STATREG(IPU_IRQ_VSYNC_PRE_0
815                         + g_dc_di_assignment[dc_chan])) &
816                         IPUIRQ_2_MASK(IPU_IRQ_VSYNC_PRE_0
817                         + g_dc_di_assignment[dc_chan]))
818                         dev_dbg(g_ipu_dev,
819                                 "VSyncPre occurred before DI%d disable\n",
820                                 g_dc_di_assignment[dc_chan]);
821         }
822 }
823
824 void _ipu_init_dc_mappings(void)
825 {
826         /* IPU_PIX_FMT_RGB24 */
827         _ipu_dc_map_clear(0);
828         _ipu_dc_map_config(0, 0, 7, 0xFF);
829         _ipu_dc_map_config(0, 1, 15, 0xFF);
830         _ipu_dc_map_config(0, 2, 23, 0xFF);
831
832         /* IPU_PIX_FMT_RGB666 */
833         _ipu_dc_map_clear(1);
834         _ipu_dc_map_config(1, 0, 5, 0xFC);
835         _ipu_dc_map_config(1, 1, 11, 0xFC);
836         _ipu_dc_map_config(1, 2, 17, 0xFC);
837
838         /* IPU_PIX_FMT_YUV444 */
839         _ipu_dc_map_clear(2);
840         _ipu_dc_map_config(2, 0, 15, 0xFF);
841         _ipu_dc_map_config(2, 1, 23, 0xFF);
842         _ipu_dc_map_config(2, 2, 7, 0xFF);
843
844         /* IPU_PIX_FMT_RGB565 */
845         _ipu_dc_map_clear(3);
846         _ipu_dc_map_config(3, 0, 4, 0xF8);
847         _ipu_dc_map_config(3, 1, 10, 0xFC);
848         _ipu_dc_map_config(3, 2, 15, 0xF8);
849
850         /* IPU_PIX_FMT_LVDS666 */
851         _ipu_dc_map_clear(4);
852         _ipu_dc_map_config(4, 0, 5, 0xFC);
853         _ipu_dc_map_config(4, 1, 13, 0xFC);
854         _ipu_dc_map_config(4, 2, 21, 0xFC);
855 }
856
857 int _ipu_pixfmt_to_map(uint32_t fmt)
858 {
859         switch (fmt) {
860         case IPU_PIX_FMT_GENERIC:
861         case IPU_PIX_FMT_RGB24:
862                 return 0;
863         case IPU_PIX_FMT_RGB666:
864                 return 1;
865         case IPU_PIX_FMT_YUV444:
866                 return 2;
867         case IPU_PIX_FMT_RGB565:
868                 return 3;
869         case IPU_PIX_FMT_LVDS666:
870                 return 4;
871         }
872
873         return -1;
874 }
875
876 /*!
877  * This function sets the colorspace for of dp.
878  * modes.
879  *
880  * @param       channel         Input parameter for the logical channel ID.
881  *
882  * @param       param           If it's not NULL, update the csc table
883  *                              with this parameter.
884  *
885  * @return      N/A
886  */
887 void _ipu_dp_set_csc_coefficients(ipu_channel_t channel, int32_t param[][3])
888 {
889         int dp;
890         struct dp_csc_param_t dp_csc_param;
891
892         if (channel == MEM_FG_SYNC)
893                 dp = DP_SYNC;
894         else if (channel == MEM_BG_SYNC)
895                 dp = DP_SYNC;
896         else if (channel == MEM_BG_ASYNC0)
897                 dp = DP_ASYNC0;
898         else
899                 return;
900
901         dp_csc_param.mode = -1;
902         dp_csc_param.coeff = param;
903         __ipu_dp_csc_setup(dp, dp_csc_param, true);
904 }
905
906 /*!
907  * This function is called to adapt synchronous LCD panel to IPU restriction.
908  *
909  */
910 void adapt_panel_to_ipu_restricitions(uint32_t *pixel_clk,
911                                       uint16_t width, uint16_t height,
912                                       uint16_t h_start_width,
913                                       uint16_t h_end_width,
914                                       uint16_t v_start_width,
915                                       uint16_t *v_end_width)
916 {
917         if (*v_end_width < 2) {
918                 uint16_t total_width = width + h_start_width + h_end_width;
919                 uint16_t total_height_old = height + v_start_width + (*v_end_width);
920                 uint16_t total_height_new = height + v_start_width + 2;
921                 *v_end_width = 2;
922                 *pixel_clk = (*pixel_clk) * total_width * total_height_new /
923                         (total_width * total_height_old);
924                 dev_err(g_ipu_dev, "WARNING: adapt panel end blank lines\n");
925         }
926 }
927
928 /*!
929  * This function is called to initialize a synchronous LCD panel.
930  *
931  * @param       disp            The DI the panel is attached to.
932  *
933  * @param       pixel_clk       Desired pixel clock frequency in Hz.
934  *
935  * @param       pixel_fmt       Input parameter for pixel format of buffer.
936  *                              Pixel format is a FOURCC ASCII code.
937  *
938  * @param       width           The width of panel in pixels.
939  *
940  * @param       height          The height of panel in pixels.
941  *
942  * @param       hStartWidth     The number of pixel clocks between the HSYNC
943  *                              signal pulse and the start of valid data.
944  *
945  * @param       hSyncWidth      The width of the HSYNC signal in units of pixel
946  *                              clocks.
947  *
948  * @param       hEndWidth       The number of pixel clocks between the end of
949  *                              valid data and the HSYNC signal for next line.
950  *
951  * @param       vStartWidth     The number of lines between the VSYNC
952  *                              signal pulse and the start of valid data.
953  *
954  * @param       vSyncWidth      The width of the VSYNC signal in units of lines
955  *
956  * @param       vEndWidth       The number of lines between the end of valid
957  *                              data and the VSYNC signal for next frame.
958  *
959  * @param       sig             Bitfield of signal polarities for LCD interface.
960  *
961  * @return      This function returns 0 on success or negative error code on
962  *              fail.
963  */
964 int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk,
965                             uint16_t width, uint16_t height,
966                             uint32_t pixel_fmt,
967                             uint16_t h_start_width, uint16_t h_sync_width,
968                             uint16_t h_end_width, uint16_t v_start_width,
969                             uint16_t v_sync_width, uint16_t v_end_width,
970                             uint32_t v_to_h_sync, ipu_di_signal_cfg_t sig)
971 {
972         unsigned long lock_flags;
973         uint32_t field0_offset = 0;
974         uint32_t field1_offset;
975         uint32_t reg;
976         uint32_t di_gen, vsync_cnt;
977         uint32_t div, rounded_pixel_clk;
978         uint32_t h_total, v_total;
979         int map;
980         int ipu_freq_scaling_enabled = 0;
981         struct clk *di_parent;
982
983         dev_dbg(g_ipu_dev, "panel size = %d x %d\n", width, height);
984
985         if ((v_sync_width == 0) || (h_sync_width == 0))
986                 return EINVAL;
987
988         adapt_panel_to_ipu_restricitions(&pixel_clk, width, height,
989                                          h_start_width, h_end_width,
990                                          v_start_width, &v_end_width);
991         h_total = width + h_sync_width + h_start_width + h_end_width;
992         v_total = height + v_sync_width + v_start_width + v_end_width;
993
994         /* Init clocking */
995         dev_dbg(g_ipu_dev, "pixel clk = %d\n", pixel_clk);
996
997         if (sig.ext_clk) {
998                 /* Set the  PLL to be an even multiple of the pixel clock. not round div for tvout*/
999                 if ((clk_get_usecount(g_pixel_clk[0]) == 0) &&
1000                                 (clk_get_usecount(g_pixel_clk[1]) == 0)) {
1001                         di_parent = clk_get_parent(g_di_clk[disp]);
1002                         if (strcmp(di_parent->name, "tve_clk") != 0 &&
1003                             strcmp(di_parent->name, "ldb_di0_clk") != 0 &&
1004                             strcmp(di_parent->name, "ldb_di1_clk") != 0)  {
1005                                 rounded_pixel_clk = pixel_clk * 2;
1006                                 while (rounded_pixel_clk < 150000000)
1007                                         rounded_pixel_clk += pixel_clk * 2;
1008                                 clk_set_rate(di_parent, rounded_pixel_clk);
1009                                 clk_set_rate(g_di_clk[disp], pixel_clk);
1010                         }
1011                 }
1012                 clk_set_parent(g_pixel_clk[disp], g_di_clk[disp]);
1013         } else {
1014                 if (clk_get_usecount(g_pixel_clk[disp]) != 0)
1015                         clk_set_parent(g_pixel_clk[disp], g_ipu_clk);
1016         }
1017         rounded_pixel_clk = clk_round_rate(g_pixel_clk[disp], pixel_clk);
1018         clk_set_rate(g_pixel_clk[disp], rounded_pixel_clk);
1019         msleep(5);
1020         /* Get integer portion of divider */
1021         div = clk_get_rate(clk_get_parent(g_pixel_clk[disp])) / rounded_pixel_clk;
1022
1023         ipu_freq_scaling_enabled = dvfs_per_pixel_clk_limit();
1024
1025         if (ipu_freq_scaling_enabled) {
1026                 /* Enable for a divide by 2 clock change. */
1027                 reg = __raw_readl(IPU_PM);
1028                 reg &= ~(0x7f << 7);
1029                 reg |= 0x20 << 7;
1030                 reg &= ~(0x7f << 23);
1031                 reg |= 0x20 << 23;
1032                 __raw_writel(reg, IPU_PM);
1033         }
1034         spin_lock_irqsave(&ipu_lock, lock_flags);
1035
1036         _ipu_di_data_wave_config(disp, SYNC_WAVE, div - 1, div - 1);
1037         _ipu_di_data_pin_config(disp, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
1038
1039         map = _ipu_pixfmt_to_map(pixel_fmt);
1040         if (map < 0) {
1041                 dev_dbg(g_ipu_dev, "IPU_DISP: No MAP\n");
1042                 spin_unlock_irqrestore(&ipu_lock, lock_flags);
1043                 return -EINVAL;
1044         }
1045
1046         di_gen = __raw_readl(DI_GENERAL(disp));
1047
1048         if (sig.interlaced) {
1049                 if (cpu_is_mx51_rev(CHIP_REV_2_0)) {
1050                         /* Setup internal HSYNC waveform */
1051                         _ipu_di_sync_config(
1052                                         disp,                   /* display */
1053                                         1,                              /* counter */
1054                                         h_total/2 - 1,  /* run count */
1055                                         DI_SYNC_CLK,             /* run_resolution */
1056                                         0,                              /* offset */
1057                                         DI_SYNC_NONE,   /* offset resolution */
1058                                         0,                              /* repeat count */
1059                                         DI_SYNC_NONE,   /* CNT_CLR_SEL */
1060                                         0,                              /* CNT_POLARITY_GEN_EN */
1061                                         DI_SYNC_NONE,   /* CNT_POLARITY_CLR_SEL */
1062                                         DI_SYNC_NONE,   /* CNT_POLARITY_TRIGGER_SEL */
1063                                         0,                              /* COUNT UP */
1064                                         0                               /* COUNT DOWN */
1065                                         );
1066
1067                         /* Field 1 VSYNC waveform */
1068                         _ipu_di_sync_config(
1069                                         disp,                   /* display */
1070                                         2,                              /* counter */
1071                                         h_total - 1,            /* run count */
1072                                         DI_SYNC_CLK,            /* run_resolution */
1073                                         0,                              /* offset */
1074                                         DI_SYNC_NONE,   /* offset resolution */
1075                                         0,                              /* repeat count */
1076                                         DI_SYNC_NONE,   /* CNT_CLR_SEL */
1077                                         0,                              /* CNT_POLARITY_GEN_EN */
1078                                         DI_SYNC_NONE,   /* CNT_POLARITY_CLR_SEL */
1079                                         DI_SYNC_NONE,   /* CNT_POLARITY_TRIGGER_SEL */
1080                                         0,                              /* COUNT UP */
1081                                         4                               /* COUNT DOWN */
1082                                         );
1083
1084                         /* Setup internal HSYNC waveform */
1085                         _ipu_di_sync_config(
1086                                         disp,                   /* display */
1087                                         3,                              /* counter */
1088                                         v_total*2 - 1,  /* run count */
1089                                         DI_SYNC_INT_HSYNC,      /* run_resolution */
1090                                         1,                              /* offset */
1091                                         DI_SYNC_INT_HSYNC,      /* offset resolution */
1092                                         0,                              /* repeat count */
1093                                         DI_SYNC_NONE,   /* CNT_CLR_SEL */
1094                                         0,                              /* CNT_POLARITY_GEN_EN */
1095                                         DI_SYNC_NONE,   /* CNT_POLARITY_CLR_SEL */
1096                                         DI_SYNC_NONE,   /* CNT_POLARITY_TRIGGER_SEL */
1097                                         0,                              /* COUNT UP */
1098                                         4                               /* COUNT DOWN */
1099                                         );
1100
1101                         /* Active Field ? */
1102                         _ipu_di_sync_config(
1103                                         disp,                   /* display */
1104                                         4,                              /* counter */
1105                                         v_total/2 - 1,  /* run count */
1106                                         DI_SYNC_HSYNC,  /* run_resolution */
1107                                         v_start_width,  /*  offset */
1108                                         DI_SYNC_HSYNC,  /* offset resolution */
1109                                         2,                              /* repeat count */
1110                                         DI_SYNC_VSYNC,  /* CNT_CLR_SEL */
1111                                         0,                              /* CNT_POLARITY_GEN_EN */
1112                                         DI_SYNC_NONE,   /* CNT_POLARITY_CLR_SEL */
1113                                         DI_SYNC_NONE,   /* CNT_POLARITY_TRIGGER_SEL */
1114                                         0,                              /* COUNT UP */
1115                                         0                               /* COUNT DOWN */
1116                                         );
1117
1118                         /* Active Line */
1119                         _ipu_di_sync_config(
1120                                         disp,                   /* display */
1121                                         5,                              /* counter */
1122                                         0,                              /* run count */
1123                                         DI_SYNC_HSYNC,  /* run_resolution */
1124                                         0,                              /*  offset */
1125                                         DI_SYNC_NONE,   /* offset resolution */
1126                                         height/2,               /* repeat count */
1127                                         4,                              /* CNT_CLR_SEL */
1128                                         0,                              /* CNT_POLARITY_GEN_EN */
1129                                         DI_SYNC_NONE,   /* CNT_POLARITY_CLR_SEL */
1130                                         DI_SYNC_NONE,   /* CNT_POLARITY_TRIGGER_SEL */
1131                                         0,                              /* COUNT UP */
1132                                         0                               /* COUNT DOWN */
1133                                         );
1134
1135                         /* Field 0 VSYNC waveform */
1136                         _ipu_di_sync_config(
1137                                         disp,                   /* display */
1138                                         6,                              /* counter */
1139                                         v_total - 1,    /* run count */
1140                                         DI_SYNC_HSYNC,  /* run_resolution */
1141                                         0,                              /* offset */
1142                                         DI_SYNC_NONE,   /* offset resolution */
1143                                         0,                              /* repeat count */
1144                                         DI_SYNC_NONE,   /* CNT_CLR_SEL  */
1145                                         0,                              /* CNT_POLARITY_GEN_EN */
1146                                         DI_SYNC_NONE,   /* CNT_POLARITY_CLR_SEL */
1147                                         DI_SYNC_NONE,   /* CNT_POLARITY_TRIGGER_SEL */
1148                                         0,                              /* COUNT UP */
1149                                         0                               /* COUNT DOWN */
1150                                         );
1151
1152                         /* DC VSYNC waveform */
1153                         vsync_cnt = 7;
1154                         _ipu_di_sync_config(
1155                                         disp,                   /* display */
1156                                         7,                              /* counter */
1157                                         v_total/2 - 1,  /* run count */
1158                                         DI_SYNC_HSYNC,  /* run_resolution  */
1159                                         9,                              /* offset  */
1160                                         DI_SYNC_HSYNC,  /* offset resolution */
1161                                         2,                              /* repeat count */
1162                                         DI_SYNC_VSYNC,  /* CNT_CLR_SEL */
1163                                         0,                              /* CNT_POLARITY_GEN_EN */
1164                                         DI_SYNC_NONE,   /* CNT_POLARITY_CLR_SEL */
1165                                         DI_SYNC_NONE,   /* CNT_POLARITY_TRIGGER_SEL */
1166                                         0,                              /* COUNT UP */
1167                                         0                               /* COUNT DOWN */
1168                                         );
1169
1170                         /* active pixel waveform */
1171                         _ipu_di_sync_config(
1172                                         disp,                   /* display */
1173                                         8,                              /* counter */
1174                                         0,      /* run count  */
1175                                         DI_SYNC_CLK,    /* run_resolution */
1176                                         h_start_width,                          /* offset  */
1177                                         DI_SYNC_CLK,    /* offset resolution */
1178                                         width,                          /* repeat count  */
1179                                         5,      /* CNT_CLR_SEL  */
1180                                         0,                              /* CNT_POLARITY_GEN_EN  */
1181                                         DI_SYNC_NONE,   /* CNT_POLARITY_CLR_SEL */
1182                                         DI_SYNC_NONE,   /* CNT_POLARITY_TRIGGER_SEL  */
1183                                         0,                              /* COUNT UP  */
1184                                         0                               /* COUNT DOWN */
1185                                         );
1186
1187                         /* ??? */
1188                         _ipu_di_sync_config(
1189                                         disp,                   /* display */
1190                                         9,                              /* counter */
1191                                         v_total - 1,    /* run count */
1192                                         DI_SYNC_INT_HSYNC,      /* run_resolution */
1193                                         v_total/2,                      /* offset  */
1194                                         DI_SYNC_INT_HSYNC,      /* offset resolution  */
1195                                         0,                              /* repeat count */
1196                                         DI_SYNC_HSYNC,  /* CNT_CLR_SEL */
1197                                         0,                              /* CNT_POLARITY_GEN_EN  */
1198                                         DI_SYNC_NONE,   /* CNT_POLARITY_CLR_SEL  */
1199                                         DI_SYNC_NONE,   /* CNT_POLARITY_TRIGGER_SEL */
1200                                         0,                              /* COUNT UP */
1201                                         4                               /* COUNT DOWN */
1202                                         );
1203
1204                         /* set gentime select and tag sel */
1205                         reg = __raw_readl(DI_SW_GEN1(disp, 9));
1206                         reg &= 0x1FFFFFFF;
1207                         reg |= (3-1)<<29 | 0x00008000;
1208                         __raw_writel(reg, DI_SW_GEN1(disp, 9));
1209
1210                         __raw_writel(v_total / 2 - 1, DI_SCR_CONF(disp));
1211
1212                         /* set y_sel = 1 */
1213                         di_gen |= 0x10000000;
1214                         di_gen |= DI_GEN_POLARITY_5;
1215                         di_gen |= DI_GEN_POLARITY_8;
1216                 } else {
1217                         /* Setup internal HSYNC waveform */
1218                         _ipu_di_sync_config(disp, 1, h_total - 1, DI_SYNC_CLK,
1219                                         0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
1220                                         DI_SYNC_NONE, 0, 0);
1221
1222                         field1_offset = v_sync_width + v_start_width + height / 2 +
1223                                 v_end_width;
1224                         if (sig.odd_field_first) {
1225                                 field0_offset = field1_offset - 1;
1226                                 field1_offset = 0;
1227                         }
1228                         v_total += v_start_width + v_end_width;
1229
1230                         /* Field 1 VSYNC waveform */
1231                         _ipu_di_sync_config(disp, 2, v_total - 1, 1,
1232                                         field0_offset,
1233                                         field0_offset ? 1 : DI_SYNC_NONE,
1234                                         0, DI_SYNC_NONE, 0,
1235                                         DI_SYNC_NONE, DI_SYNC_NONE, 0, 4);
1236
1237                         /* Setup internal HSYNC waveform */
1238                         _ipu_di_sync_config(disp, 3, h_total - 1, DI_SYNC_CLK,
1239                                         0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0,
1240                                         DI_SYNC_NONE, DI_SYNC_NONE, 0, 4);
1241
1242                         /* Active Field ? */
1243                         _ipu_di_sync_config(disp, 4,
1244                                         field0_offset ?
1245                                         field0_offset : field1_offset - 2,
1246                                         1, v_start_width + v_sync_width, 1, 2, 2,
1247                                         0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0);
1248
1249                         /* Active Line */
1250                         _ipu_di_sync_config(disp, 5, 0, 1,
1251                                         0, DI_SYNC_NONE,
1252                                         height / 2, 4, 0, DI_SYNC_NONE,
1253                                         DI_SYNC_NONE, 0, 0);
1254
1255                         /* Field 0 VSYNC waveform */
1256                         _ipu_di_sync_config(disp, 6, v_total - 1, 1,
1257                                         0, DI_SYNC_NONE,
1258                                         0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
1259                                         DI_SYNC_NONE, 0, 0);
1260
1261                         /* DC VSYNC waveform */
1262                         vsync_cnt = 7;
1263                         _ipu_di_sync_config(disp, 7, 0, 1,
1264                                         field1_offset,
1265                                         field1_offset ? 1 : DI_SYNC_NONE,
1266                                         1, 2, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0);
1267
1268                         /* active pixel waveform */
1269                         _ipu_di_sync_config(disp, 8, 0, DI_SYNC_CLK,
1270                                         h_sync_width + h_start_width, DI_SYNC_CLK,
1271                                         width, 5, 0, DI_SYNC_NONE, DI_SYNC_NONE,
1272                                         0, 0);
1273
1274                         /* ??? */
1275                         _ipu_di_sync_config(disp, 9, v_total - 1, 2,
1276                                         0, DI_SYNC_NONE,
1277                                         0, DI_SYNC_NONE, 6, DI_SYNC_NONE,
1278                                         DI_SYNC_NONE, 0, 0);
1279
1280                         reg = __raw_readl(DI_SW_GEN1(disp, 9));
1281                         reg |= 0x8000;
1282                         __raw_writel(reg, DI_SW_GEN1(disp, 9));
1283
1284                         __raw_writel(v_sync_width + v_start_width +
1285                                         v_end_width + height / 2 - 1, DI_SCR_CONF(disp));
1286                 }
1287
1288                 /* Init template microcode */
1289                 _ipu_dc_write_tmpl(0, WROD(0), 0, map, SYNC_WAVE, 0, 8);
1290
1291                 if (sig.Hsync_pol)
1292                         di_gen |= DI_GEN_POLARITY_3;
1293                 if (sig.Vsync_pol)
1294                         di_gen |= DI_GEN_POLARITY_2;
1295         } else {
1296                 /* Setup internal HSYNC waveform */
1297                 _ipu_di_sync_config(disp, 1, h_total - 1, DI_SYNC_CLK,
1298                                         0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
1299                                         DI_SYNC_NONE, 0, 0);
1300
1301                 /* Setup external (delayed) HSYNC waveform */
1302                 _ipu_di_sync_config(disp, DI_SYNC_HSYNC, h_total - 1,
1303                                     DI_SYNC_CLK, div * v_to_h_sync, DI_SYNC_CLK,
1304                                     0, DI_SYNC_NONE, 1, DI_SYNC_NONE,
1305                                     DI_SYNC_CLK, 0, h_sync_width * 2);
1306                 /* Setup VSYNC waveform */
1307                 vsync_cnt = DI_SYNC_VSYNC;
1308                 _ipu_di_sync_config(disp, DI_SYNC_VSYNC, v_total - 1,
1309                                     DI_SYNC_INT_HSYNC, 0, DI_SYNC_NONE, 0,
1310                                     DI_SYNC_NONE, 1, DI_SYNC_NONE,
1311                                     DI_SYNC_INT_HSYNC, 0, v_sync_width * 2);
1312                 __raw_writel(v_total - 1, DI_SCR_CONF(disp));
1313
1314                 /* Setup active data waveform to sync with DC */
1315                 _ipu_di_sync_config(disp, 4, 0, DI_SYNC_HSYNC,
1316                                     v_sync_width + v_start_width, DI_SYNC_HSYNC, height,
1317                                     DI_SYNC_VSYNC, 0, DI_SYNC_NONE,
1318                                     DI_SYNC_NONE, 0, 0);
1319                 _ipu_di_sync_config(disp, 5, 0, DI_SYNC_CLK,
1320                                     h_sync_width + h_start_width, DI_SYNC_CLK,
1321                                     width, 4, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0,
1322                                     0);
1323
1324                 /* reset all unused counters */
1325                 __raw_writel(0, DI_SW_GEN0(disp, 6));
1326                 __raw_writel(0, DI_SW_GEN1(disp, 6));
1327                 __raw_writel(0, DI_SW_GEN0(disp, 7));
1328                 __raw_writel(0, DI_SW_GEN1(disp, 7));
1329                 __raw_writel(0, DI_SW_GEN0(disp, 8));
1330                 __raw_writel(0, DI_SW_GEN1(disp, 8));
1331                 __raw_writel(0, DI_SW_GEN0(disp, 9));
1332                 __raw_writel(0, DI_SW_GEN1(disp, 9));
1333
1334                 reg = __raw_readl(DI_STP_REP(disp, 6));
1335                 reg &= 0x0000FFFF;
1336                 __raw_writel(reg, DI_STP_REP(disp, 6));
1337                 __raw_writel(0, DI_STP_REP(disp, 7));
1338                 __raw_writel(0, DI_STP_REP(disp, 9));
1339
1340                 if (ipu_freq_scaling_enabled) {
1341                         h_total = ((width + h_start_width +
1342                                         h_sync_width) / 2) - 2;
1343                         _ipu_di_sync_config(disp, 6, 1, 0,
1344                                 2, DI_SYNC_CLK,
1345                                 h_total,
1346                                 DI_SYNC_INT_HSYNC, 0, DI_SYNC_NONE,
1347                                 DI_SYNC_NONE, 0, 0);
1348                 }
1349
1350                 /* Init template microcode */
1351                 if (disp) {
1352                    _ipu_dc_write_tmpl(2, WROD(0), 0, map, SYNC_WAVE, 8, 5);
1353                    _ipu_dc_write_tmpl(3, WROD(0), 0, map, SYNC_WAVE, 4, 5);
1354                    _ipu_dc_write_tmpl(4, WROD(0), 0, map, SYNC_WAVE, 0, 5);
1355                 } else {
1356                    _ipu_dc_write_tmpl(5, WROD(0), 0, map, SYNC_WAVE, 8, 5);
1357                    _ipu_dc_write_tmpl(6, WROD(0), 0, map, SYNC_WAVE, 4, 5);
1358                    _ipu_dc_write_tmpl(7, WROD(0), 0, map, SYNC_WAVE, 0, 5);
1359                 }
1360
1361                 if (sig.Hsync_pol)
1362                         di_gen |= DI_GEN_POLARITY_2;
1363                 if (sig.Vsync_pol)
1364                         di_gen |= DI_GEN_POLARITY_3;
1365
1366                 if (ipu_freq_scaling_enabled)
1367                         /* Set the clock to stop at counter 6. */
1368                         di_gen |= 0x6000000;
1369         }
1370
1371         __raw_writel(di_gen, DI_GENERAL(disp));
1372
1373         if (!ipu_freq_scaling_enabled)
1374                 __raw_writel((--vsync_cnt << DI_VSYNC_SEL_OFFSET) |
1375                                         0x00000002, DI_SYNC_AS_GEN(disp));
1376         else {
1377                 if (sig.interlaced)
1378                         __raw_writel((--vsync_cnt << DI_VSYNC_SEL_OFFSET) |
1379                                         0x00000002, DI_SYNC_AS_GEN(disp));
1380                 else
1381                         __raw_writel((--vsync_cnt << DI_VSYNC_SEL_OFFSET),
1382                                         DI_SYNC_AS_GEN(disp));
1383         }
1384
1385         reg = __raw_readl(DI_POL(disp));
1386         reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
1387         if (sig.enable_pol)
1388                 reg |= DI_POL_DRDY_POLARITY_15;
1389         if (sig.data_pol)
1390                 reg |= DI_POL_DRDY_DATA_POLARITY;
1391         __raw_writel(reg, DI_POL(disp));
1392
1393         __raw_writel(width, DC_DISP_CONF2(DC_DISP_ID_SYNC(disp)));
1394
1395         spin_unlock_irqrestore(&ipu_lock, lock_flags);
1396
1397         return 0;
1398 }
1399 EXPORT_SYMBOL(ipu_init_sync_panel);
1400
1401
1402 int ipu_init_async_panel(int disp, int type, uint32_t cycle_time,
1403                          uint32_t pixel_fmt, ipu_adc_sig_cfg_t sig)
1404 {
1405         unsigned long lock_flags;
1406         int map;
1407         u32 ser_conf = 0;
1408         u32 div;
1409         u32 di_clk = clk_get_rate(g_ipu_clk);
1410
1411         /* round up cycle_time, then calcalate the divider using scaled math */
1412         cycle_time += (1000000000UL / di_clk) - 1;
1413         div = (cycle_time * (di_clk / 256UL)) / (1000000000UL / 256UL);
1414
1415         map = _ipu_pixfmt_to_map(pixel_fmt);
1416         if (map < 0)
1417                 return -EINVAL;
1418
1419         spin_lock_irqsave(&ipu_lock, lock_flags);
1420
1421         if (type == IPU_PANEL_SERIAL) {
1422                 __raw_writel((div << 24) | ((sig.ifc_width - 1) << 4),
1423                              DI_DW_GEN(disp, ASYNC_SER_WAVE));
1424
1425                 _ipu_di_data_pin_config(disp, ASYNC_SER_WAVE, DI_PIN_CS,
1426                                         0, 0, (div * 2) + 1);
1427                 _ipu_di_data_pin_config(disp, ASYNC_SER_WAVE, DI_PIN_SER_CLK,
1428                                         1, div, div * 2);
1429                 _ipu_di_data_pin_config(disp, ASYNC_SER_WAVE, DI_PIN_SER_RS,
1430                                         2, 0, 0);
1431
1432                 _ipu_dc_write_tmpl(0x64, WROD(0), 0, map, ASYNC_SER_WAVE, 0, 0);
1433
1434                 /* Configure DC for serial panel */
1435                 __raw_writel(0x14, DC_DISP_CONF1(DC_DISP_ID_SERIAL));
1436
1437                 if (sig.clk_pol)
1438                         ser_conf |= DI_SER_CONF_SERIAL_CLK_POL;
1439                 if (sig.data_pol)
1440                         ser_conf |= DI_SER_CONF_SERIAL_DATA_POL;
1441                 if (sig.rs_pol)
1442                         ser_conf |= DI_SER_CONF_SERIAL_RS_POL;
1443                 if (sig.cs_pol)
1444                         ser_conf |= DI_SER_CONF_SERIAL_CS_POL;
1445                 __raw_writel(ser_conf, DI_SER_CONF(disp));
1446         }
1447
1448         spin_unlock_irqrestore(&ipu_lock, lock_flags);
1449         return 0;
1450 }
1451 EXPORT_SYMBOL(ipu_init_async_panel);
1452
1453 /*!
1454  * This function sets the foreground and background plane global alpha blending
1455  * modes. This function also sets the DP graphic plane according to the
1456  * parameter of IPUv3 DP channel.
1457  *
1458  * @param       channel         IPUv3 DP channel
1459  *
1460  * @param       enable          Boolean to enable or disable global alpha
1461  *                              blending. If disabled, local blending is used.
1462  *
1463  * @param       alpha           Global alpha value.
1464  *
1465  * @return      Returns 0 on success or negative error code on fail
1466  */
1467 int32_t ipu_disp_set_global_alpha(ipu_channel_t channel, bool enable,
1468                                   uint8_t alpha)
1469 {
1470         uint32_t reg;
1471         uint32_t flow;
1472         unsigned long lock_flags;
1473         bool bg_chan;
1474
1475         if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC)
1476                 flow = DP_SYNC;
1477         else if (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0)
1478                 flow = DP_ASYNC0;
1479         else if (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1)
1480                 flow = DP_ASYNC1;
1481         else
1482                 return -EINVAL;
1483
1484         if (channel == MEM_BG_SYNC || channel == MEM_BG_ASYNC0 ||
1485             channel == MEM_BG_ASYNC1)
1486                 bg_chan = true;
1487         else
1488                 bg_chan = false;
1489
1490         if (!g_ipu_clk_enabled)
1491                 clk_enable(g_ipu_clk);
1492         spin_lock_irqsave(&ipu_lock, lock_flags);
1493
1494         if (bg_chan) {
1495                 reg = __raw_readl(DP_COM_CONF(flow));
1496                 __raw_writel(reg & ~DP_COM_CONF_GWSEL, DP_COM_CONF(flow));
1497         } else {
1498                 reg = __raw_readl(DP_COM_CONF(flow));
1499                 __raw_writel(reg | DP_COM_CONF_GWSEL, DP_COM_CONF(flow));
1500         }
1501
1502         if (enable) {
1503                 reg = __raw_readl(DP_GRAPH_WIND_CTRL(flow)) & 0x00FFFFFFL;
1504                 __raw_writel(reg | ((uint32_t) alpha << 24),
1505                              DP_GRAPH_WIND_CTRL(flow));
1506
1507                 reg = __raw_readl(DP_COM_CONF(flow));
1508                 __raw_writel(reg | DP_COM_CONF_GWAM, DP_COM_CONF(flow));
1509         } else {
1510                 reg = __raw_readl(DP_COM_CONF(flow));
1511                 __raw_writel(reg & ~DP_COM_CONF_GWAM, DP_COM_CONF(flow));
1512         }
1513
1514         reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
1515         __raw_writel(reg, IPU_SRM_PRI2);
1516
1517         spin_unlock_irqrestore(&ipu_lock, lock_flags);
1518         if (!g_ipu_clk_enabled)
1519                 clk_disable(g_ipu_clk);
1520
1521         return 0;
1522 }
1523 EXPORT_SYMBOL(ipu_disp_set_global_alpha);
1524
1525 /*!
1526  * This function sets the transparent color key for SDC graphic plane.
1527  *
1528  * @param       channel         Input parameter for the logical channel ID.
1529  *
1530  * @param       enable          Boolean to enable or disable color key
1531  *
1532  * @param       colorKey        24-bit RGB color for transparent color key.
1533  *
1534  * @return      Returns 0 on success or negative error code on fail
1535  */
1536 int32_t ipu_disp_set_color_key(ipu_channel_t channel, bool enable,
1537                                uint32_t color_key)
1538 {
1539         uint32_t reg, flow;
1540         int y, u, v;
1541         int red, green, blue;
1542         unsigned long lock_flags;
1543
1544         if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC)
1545                 flow = DP_SYNC;
1546         else if (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0)
1547                 flow = DP_ASYNC0;
1548         else if (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1)
1549                 flow = DP_ASYNC1;
1550         else
1551                 return -EINVAL;
1552
1553         if (!g_ipu_clk_enabled)
1554                 clk_enable(g_ipu_clk);
1555
1556         spin_lock_irqsave(&ipu_lock, lock_flags);
1557
1558         color_key_4rgb = 1;
1559         /* Transform color key from rgb to yuv if CSC is enabled */
1560         if (((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) ||
1561                         ((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) ||
1562                         ((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) ||
1563                         ((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB))) {
1564
1565                 dev_dbg(g_ipu_dev, "color key 0x%x need change to yuv fmt\n", color_key);
1566
1567                 red = (color_key >> 16) & 0xFF;
1568                 green = (color_key >> 8) & 0xFF;
1569                 blue = color_key & 0xFF;
1570
1571                 y = _rgb_to_yuv(0, red, green, blue);
1572                 u = _rgb_to_yuv(1, red, green, blue);
1573                 v = _rgb_to_yuv(2, red, green, blue);
1574                 color_key = (y << 16) | (u << 8) | v;
1575
1576                 color_key_4rgb = 0;
1577
1578                 dev_dbg(g_ipu_dev, "color key change to yuv fmt 0x%x\n", color_key);
1579         }
1580
1581         if (enable) {
1582                 reg = __raw_readl(DP_GRAPH_WIND_CTRL(flow)) & 0xFF000000L;
1583                 __raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL(flow));
1584
1585                 reg = __raw_readl(DP_COM_CONF(flow));
1586                 __raw_writel(reg | DP_COM_CONF_GWCKE, DP_COM_CONF(flow));
1587         } else {
1588                 reg = __raw_readl(DP_COM_CONF(flow));
1589                 __raw_writel(reg & ~DP_COM_CONF_GWCKE, DP_COM_CONF(flow));
1590         }
1591
1592         reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
1593         __raw_writel(reg, IPU_SRM_PRI2);
1594
1595         spin_unlock_irqrestore(&ipu_lock, lock_flags);
1596         if (!g_ipu_clk_enabled)
1597                 clk_disable(g_ipu_clk);
1598
1599         return 0;
1600 }
1601 EXPORT_SYMBOL(ipu_disp_set_color_key);
1602
1603 /*!
1604  * This function sets the gamma correction for DP output.
1605  *
1606  * @param       channel         Input parameter for the logical channel ID.
1607  *
1608  * @param       enable          Boolean to enable or disable gamma correction.
1609  *
1610  * @param       constk          Gamma piecewise linear approximation constk coeff.
1611  *
1612  * @param       slopek          Gamma piecewise linear approximation slopek coeff.
1613  *
1614  * @return      Returns 0 on success or negative error code on fail
1615  */
1616 int32_t ipu_disp_set_gamma_correction(ipu_channel_t channel, bool enable, int constk[], int slopek[])
1617 {
1618         uint32_t reg, flow, i;
1619         unsigned long lock_flags;
1620
1621         if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC)
1622                 flow = DP_SYNC;
1623         else if (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0)
1624                 flow = DP_ASYNC0;
1625         else if (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1)
1626                 flow = DP_ASYNC1;
1627         else
1628                 return -EINVAL;
1629
1630         if (!g_ipu_clk_enabled)
1631                 clk_enable(g_ipu_clk);
1632         spin_lock_irqsave(&ipu_lock, lock_flags);
1633
1634         for (i = 0; i < 8; i++)
1635                 __raw_writel((constk[2*i] & 0x1ff) | ((constk[2*i+1] & 0x1ff) << 16), DP_GAMMA_C(flow, i));
1636         for (i = 0; i < 4; i++)
1637                 __raw_writel((slopek[4*i] & 0xff) | ((slopek[4*i+1] & 0xff) << 8) |
1638                         ((slopek[4*i+2] & 0xff) << 16) | ((slopek[4*i+3] & 0xff) << 24), DP_GAMMA_S(flow, i));
1639
1640         reg = __raw_readl(DP_COM_CONF(flow));
1641         if (enable) {
1642                 if ((bg_csc_type == RGB2YUV) || (bg_csc_type == YUV2YUV))
1643                         reg |= DP_COM_CONF_GAMMA_YUV_EN;
1644                 else
1645                         reg &= ~DP_COM_CONF_GAMMA_YUV_EN;
1646                 __raw_writel(reg | DP_COM_CONF_GAMMA_EN, DP_COM_CONF(flow));
1647         } else
1648                 __raw_writel(reg & ~DP_COM_CONF_GAMMA_EN, DP_COM_CONF(flow));
1649
1650         reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
1651         __raw_writel(reg, IPU_SRM_PRI2);
1652
1653         spin_unlock_irqrestore(&ipu_lock, lock_flags);
1654         if (!g_ipu_clk_enabled)
1655                 clk_disable(g_ipu_clk);
1656
1657         return 0;
1658 }
1659 EXPORT_SYMBOL(ipu_disp_set_gamma_correction);
1660
1661 /*!
1662  * This function sets the window position of the foreground or background plane.
1663  * modes.
1664  *
1665  * @param       channel         Input parameter for the logical channel ID.
1666  *
1667  * @param       x_pos           The X coordinate position to place window at.
1668  *                              The position is relative to the top left corner.
1669  *
1670  * @param       y_pos           The Y coordinate position to place window at.
1671  *                              The position is relative to the top left corner.
1672  *
1673  * @return      Returns 0 on success or negative error code on fail
1674  */
1675 int32_t ipu_disp_set_window_pos(ipu_channel_t channel, int16_t x_pos,
1676                                 int16_t y_pos)
1677 {
1678         u32 reg;
1679         unsigned long lock_flags;
1680         uint32_t flow = 0;
1681
1682         if (channel == MEM_FG_SYNC)
1683                 flow = DP_SYNC;
1684         else if (channel == MEM_FG_ASYNC0)
1685                 flow = DP_ASYNC0;
1686         else if (channel == MEM_FG_ASYNC1)
1687                 flow = DP_ASYNC1;
1688         else
1689                 return -EINVAL;
1690
1691         if (!g_ipu_clk_enabled)
1692                 clk_enable(g_ipu_clk);
1693
1694         spin_lock_irqsave(&ipu_lock, lock_flags);
1695
1696         __raw_writel((x_pos << 16) | y_pos, DP_FG_POS(flow));
1697
1698         reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
1699         __raw_writel(reg, IPU_SRM_PRI2);
1700
1701         spin_unlock_irqrestore(&ipu_lock, lock_flags);
1702         if (!g_ipu_clk_enabled)
1703                 clk_disable(g_ipu_clk);
1704
1705         return 0;
1706 }
1707 EXPORT_SYMBOL(ipu_disp_set_window_pos);
1708
1709 void ipu_disp_direct_write(ipu_channel_t channel, u32 value, u32 offset)
1710 {
1711         if (channel == DIRECT_ASYNC0)
1712                 __raw_writel(value, ipu_disp_base[0] + offset);
1713         else if (channel == DIRECT_ASYNC1)
1714                 __raw_writel(value, ipu_disp_base[1] + offset);
1715 }
1716 EXPORT_SYMBOL(ipu_disp_direct_write);
1717
1718 void ipu_reset_disp_panel(void)
1719 {
1720         uint32_t tmp;
1721
1722         tmp = __raw_readl(DI_GENERAL(1));
1723         __raw_writel(tmp | 0x08, DI_GENERAL(1));
1724         msleep(10); /* tRES >= 100us */
1725         tmp = __raw_readl(DI_GENERAL(1));
1726         __raw_writel(tmp & ~0x08, DI_GENERAL(1));
1727         msleep(60);
1728
1729         return;
1730 }
1731 EXPORT_SYMBOL(ipu_reset_disp_panel);