rk3288 hdmi: add support csc function that RGB to YCbCr and RGB_0_255 to RGB_16_235
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / hdmi / rk_hdmi_lcdc.c
1 #include <linux/console.h>
2 #include<linux/rk_fb.h>
3 #include "rk_hdmi.h"
4
5 #define OUT_TYPE                SCREEN_HDMI
6 #define OUT_FACE                OUT_P888
7 #define DCLK_POL                1
8 #define SWAP_RB                 0
9 #define LCD_ACLK                800000000
10
11 static struct hdmi *m_hdmi_drv = NULL;
12
13 static const struct fb_videomode hdmi_mode [] = {
14         //name                  refresh         xres    yres    pixclock        h_bp    h_fp    v_bp    v_fp    h_pw    v_pw    polariry                                                        PorI    flag(used for vic)
15 //{     "640x480p@60Hz",                60,             640,    480,    25175000,       48,     16,     33,     10,     96,     2,      0,      0,      1       },
16 //{     "720x480i@60Hz",                60,             720,    480,    27000000,       114,    38,     15,     4,      124,    3,      0,      1,      6       },
17 //{     "720x576i@50Hz",                50,             720,    576,    27000000,       138,    24,     19,     2,      126,    3,      0,      1,      21      },
18 {       "720x480p@60Hz",        60,             720,    480,    27000000,       60,     16,     30,     9,      62,     6,      0,      0,      2       },
19 {       "720x576p@50Hz",        50,             720,    576,    27000000,       68,     12,     39,     5,      64,     5,      0,      0,      17      },
20 //{     "1280x720p@24Hz",       24,             1280,   720,    59400000,       220,    1760,   20,     5,      40,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              60      },
21 //{     "1280x720p@25Hz",       25,             1280,   720,    74250000,       220,    2420,   20,     5,      40,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              61      },
22 //{     "1280x720p@30Hz",       30,             1280,   720,    74250000,       220,    1760,   20,     5,      40,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              62      },
23 {       "1280x720p@50Hz",       50,             1280,   720,    74250000,       220,    440,    20,     5,      40,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              19      },
24 {       "1280x720p@60Hz",       60,             1280,   720,    74250000,       220,    110,    20,     5,      40,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              4       },
25 //{     "1920x1080p@24Hz",      24,             1920,   1080,   74250000,       148,    638,    36,     4,      44,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              32      },
26 //{     "1920x1080p@25Hz",      25,             1920,   1080,   74250000,       148,    528,    36,     4,      44,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              33      },
27 //{     "1920x1080p@30Hz",      30,             1920,   1080,   74250000,       148,    88,     36,     4,      44,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              34      },      
28 //{     "1920x1080i@50Hz_2",    50,             1920,   1080,   72000000,       184,    32,     57,     23,     168,    5,      FB_SYNC_HOR_HIGH_ACT,                   1,              39      },
29 //{     "1920x1080i@50Hz",      50,             1920,   1080,   74250000,       148,    528,    15,     2,      44,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   1,              20      },
30 //{     "1920x1080i@60Hz",      60,             1920,   1080,   74250000,       148,    88,     15,     2,      44,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   1,              5       },
31 {       "1920x1080p@50Hz",      50,             1920,   1080,   148500000,      148,    528,    36,     4,      44,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              31      },
32 {       "1920x1080p@60Hz",      60,             1920,   1080,   148500000,      148,    88,     36,     4,      44,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              16      },
33 /*
34 {       "1440x288p@50Hz",       50,             720,    480,    27000000,       138,    24,     19,     2,      126,    3,              0,                      0,              23      },
35 {       "2880x576i@50Hz",       50,             1440,   240,    54000000,       276,    48,     19,     2,      252,    3,              0,                      1,              25      },
36 {       "2880x288p@50Hz",       50,             2880,   480,    54000000,       276,    48,     19,     3,      252,    3,              0,                      0,              27      },
37 {       "1440x576p@50Hz",       50,             2880,   480,    54000000,       136,    24,     39,     5,      128,    5,              0,                      0,              29      },
38 {       "2880x576p@50Hz",       50,             1920,   1080,   108000000,      272,    48,     39,     5,      256,    5,              0,                      0,              37      },
39 {       "1440x240p@60Hz",       60,             1440,   240,    27000000,       114,    38,     15,     4,      124,    3,              0,                      0,              8       },
40 {       "2880x480i@60Hz",       60,             2880,   480,    54000000,       228,    76,     15,     4,      248,    3,              0,                      1,              10      },
41 {       "2880x480p@60Hz",       60,             2880,   480,    54000000,       228,    76,     15,     4,      248,    3,              0,                      0,              12      },
42 {       "1440x480p@60Hz",       60,             1440,   480,    54000000,       120,    32,     30,     9,      124,    6,              0,                      0,              14      },
43 {       "2880x480p@60Hz",       60,             2880,   480,    54000000,       240,    64,     30,     9,      248,    6,              0,                      0,              35      },
44
45 {       "1920x1080i@100Hz",     100,            1920,   1080,   148500000,      148,    528,    15,     2,      44,     5,              1,                      1,              40      },
46 {       "1280x720p@100Hz",      100,            1280,   720,    148500000,      220,    440,    20,     5,      40,     5,              1,                      0,              41      },
47 {       "720x576p@100Hz",       100,            720,    576,    54000000,       68,             12,     39,     5,      64,             5,              0,                      0,              42      },
48 {       "1440x576i@100Hz",      100,            1440,   576,    54000000,       138,    24,     19,     2,      12,     3,              0,                      1,              44      },
49 {       "1920x1080p@100Hz",     100,            1920,   1080,   297000000,      148,    528,    36,     4,      44,     5,              1,                      0,              64      },
50
51 {       "1920x1080i@120Hz",     120,            1920,   1080,   148500000,      148,    88,     15,     2,      44,     5,              1,                      1,              46      },
52 {       "1280x720p@120Hz",      120,            1280,   720,    148500000,      220,    110,    20,     5,      40,     5,              1,                      0,              47      },
53 {       "720x480p@120Hz",       120,            720,    480,    54000000,       60,             16,     30,     9,      62,             6,              0,                      0,              48      },
54 {       "1440x480i@120Hz",      120,            1440,   480,    54000000,       114,    38,     15,     4,      12,     3,              0,                      1,              50      },
55 {       "1920x1080p@120Hz",     120,            1920,   1080,   297000000,      148,    88,     36,     4,      44,     5,              1,                      0,              63      },
56
57 {       "720x576p@200Hz",       200,            720,    576,    108000000,      68,     12,     39,     5,      64,     5,              0,                      0,              52      },
58 {       "1440x576i@200Hz",      200,            1920,   1080,   108000000,      138,    24,     19,     2,      12,     3,              0,                      1,              54      },
59
60 {       "720x480p@240Hz",       240,            720,    480,    108000000,      60,     16,     30,     9,      62,     6,              0,                      0,              56      },
61 {       "1440x480i@240Hz",      240,            1440,   480,    108000000,      114,    38,     15,     4,      12,     3,              0,                      1,              58      },
62 */
63 {       "3840x2160p@24Hz",      24,             3840,   2160,   297000000,      296,    1276,   72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              93      },
64 {       "3840x2160p@25Hz",      25,             3840,   2160,   297000000,      296,    1056,   72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              94      },
65 {       "3840x2160p@30Hz",      30,             3840,   2160,   297000000,      296,    176,    72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              95      },
66 {       "3840x2160p@50Hz",      50,             3840,   2160,   594000000,      296,    1056,   72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              96      },
67 {       "3840x2160p@60Hz",      60,             3840,   2160,   594000000,      296,    176,    72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              97      },
68 {       "4096x2160p@24Hz",      24,             4096,   2160,   297000000,      296,    1020,   72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              98      },
69 {       "4096x2160p@25Hz",      25,             4096,   2160,   297000000,      128,    968,    72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              99      },
70 {       "4096x2160p@30Hz",      30,             4096,   2160,   297000000,      128,    88,     72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              100     },
71 {       "4096x2160p@50Hz",      50,             4096,   2160,   594000000,      128,    968,    72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              101     },
72 {       "4096x2160p@60Hz",      60,             4096,   2160,   594000000,      128,    88,     72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              102     },
73
74 };
75
76 void hdmi_init_lcdc(struct rk_screen *screen, struct rk29lcd_info *lcd_info)
77 {
78         hdmi_set_info(screen, HDMI_VIDEO_DEFAULT_MODE);
79 }
80
81 int hdmi_set_info(struct rk_screen *screen, unsigned int vic)
82 {
83     int i;
84     
85     if(screen == NULL)
86         return -1;
87     
88     if(vic == 0)
89         vic = HDMI_VIDEO_DEFAULT_MODE;
90         
91     for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
92     {
93         if(hdmi_mode[i].flag == vic)
94                 break;
95     }
96     if(i == ARRAY_SIZE(hdmi_mode))
97         return -1;
98     
99     memset(screen, 0, sizeof(struct rk_screen));
100     
101     /* screen type & face */
102     screen->type = OUT_TYPE;
103     screen->face = OUT_FACE;
104
105     /* Screen size */
106     screen->mode.xres = hdmi_mode[i].xres;
107     screen->mode.yres = hdmi_mode[i].yres;
108     
109     /* Timing */
110     screen->mode.pixclock = hdmi_mode[i].pixclock;
111     screen->mode.refresh = hdmi_mode[i].refresh;
112         //screen->lcdc_aclk = LCD_ACLK;
113         screen->mode.left_margin = hdmi_mode[i].left_margin;
114         screen->mode.right_margin = hdmi_mode[i].right_margin;
115         screen->mode.hsync_len = hdmi_mode[i].hsync_len;
116         screen->mode.upper_margin = hdmi_mode[i].upper_margin;
117         screen->mode.lower_margin = hdmi_mode[i].lower_margin;
118         screen->mode.vsync_len = hdmi_mode[i].vsync_len;
119         screen->hdmi_resolution = hdmi_mode[i].flag;
120
121         /* Pin polarity */
122 #if defined(CONFIG_HDMI_RK616) && !defined(CONFIG_ARCH_RK3026)
123         screen->pin_hsync = 0;
124         screen->pin_vsync = 0;
125 #else 
126         screen->pin_hsync = 0;
127         if(FB_SYNC_HOR_HIGH_ACT & hdmi_mode[i].sync)
128                 screen->pin_hsync = 1;
129         else
130                 screen->pin_hsync = 0;
131         if(FB_SYNC_VERT_HIGH_ACT & hdmi_mode[i].sync)
132                 screen->pin_vsync = 1;
133         else
134                 screen->pin_vsync = 0;
135 #endif
136         screen->pin_den = 0;
137         screen->pin_dclk = DCLK_POL;
138
139         /* Swap rule */
140     screen->swap_rb = SWAP_RB;
141     screen->swap_rg = 0;
142     screen->swap_gb = 0;
143     screen->swap_delta = 0;
144     screen->swap_dumy = 0;
145
146     /* Operation function*/
147     screen->init = NULL;
148     screen->standby = NULL;
149     
150     return 0;
151 }
152
153 static void hdmi_show_sink_info(struct hdmi *hdmi)
154 {
155         struct list_head *pos, *head = &hdmi->edid.modelist;
156         struct fb_modelist *modelist;
157         struct fb_videomode *m;
158         int i;
159         struct hdmi_audio *audio;
160
161         hdmi_dbg(hdmi->dev, "******** Show Sink Info ********\n");
162         hdmi_dbg(hdmi->dev, "Support video mode: \n");
163         list_for_each(pos, head) {
164                 modelist = list_entry(pos, struct fb_modelist, list);
165                 m = &modelist->mode;
166                 hdmi_dbg(hdmi->dev, "   %s.\n", m->name);
167         }
168         
169         for(i = 0; i < hdmi->edid.audio_num; i++)
170         {
171                 audio = &(hdmi->edid.audio[i]);
172                 switch(audio->type)
173                 {
174                         case HDMI_AUDIO_LPCM:
175                                 hdmi_dbg(hdmi->dev, "Support audio type: LPCM\n");
176                                 break;
177                         case HDMI_AUDIO_AC3:
178                                 hdmi_dbg(hdmi->dev, "Support audio type: AC3\n");
179                                 break;
180                         case HDMI_AUDIO_MPEG1:
181                                 hdmi_dbg(hdmi->dev, "Support audio type: MPEG1\n");
182                                 break;
183                         case HDMI_AUDIO_MP3:
184                                 hdmi_dbg(hdmi->dev, "Support audio type: MP3\n");
185                                 break;
186                         case HDMI_AUDIO_MPEG2:
187                                 hdmi_dbg(hdmi->dev, "Support audio type: MPEG2\n");
188                                 break;
189                         case HDMI_AUDIO_AAC_LC:
190                                 hdmi_dbg(hdmi->dev, "Support audio type: AAC\n");
191                                 break;
192                         case HDMI_AUDIO_DTS:
193                                 hdmi_dbg(hdmi->dev, "Support audio type: DTS\n");
194                                 break;
195                         case HDMI_AUDIO_ATARC:
196                                 hdmi_dbg(hdmi->dev, "Support audio type: ATARC\n");
197                                 break;
198                         case HDMI_AUDIO_DSD:
199                                 hdmi_dbg(hdmi->dev, "Support audio type: DSD\n");
200                                 break;
201                         case HDMI_AUDIO_E_AC3:
202                                 hdmi_dbg(hdmi->dev, "Support audio type: E-AC3\n");
203                                 break;
204                         case HDMI_AUDIO_DTS_HD:
205                                 hdmi_dbg(hdmi->dev, "Support audio type: DTS-HD\n");
206                                 break;
207                         case HDMI_AUDIO_MLP:
208                                 hdmi_dbg(hdmi->dev, "Support audio type: MLP\n");
209                                 break;
210                         case HDMI_AUDIO_DST:
211                                 hdmi_dbg(hdmi->dev, "Support audio type: DST\n");
212                                 break;
213                         case HDMI_AUDIO_WMA_PRO:
214                                 hdmi_dbg(hdmi->dev, "Support audio type: WMP-PRO\n");
215                                 break;
216                         default:
217                                 hdmi_dbg(hdmi->dev, "Support audio type: Unkown\n");
218                                 break;
219                 }
220                 
221                 hdmi_dbg(hdmi->dev, "Support audio sample rate: \n");
222                 if(audio->rate & HDMI_AUDIO_FS_32000)
223                         hdmi_dbg(hdmi->dev, "   32000\n");
224                 if(audio->rate & HDMI_AUDIO_FS_44100)
225                         hdmi_dbg(hdmi->dev, "   44100\n");
226                 if(audio->rate & HDMI_AUDIO_FS_48000)
227                         hdmi_dbg(hdmi->dev, "   48000\n");
228                 if(audio->rate & HDMI_AUDIO_FS_88200)
229                         hdmi_dbg(hdmi->dev, "   88200\n");
230                 if(audio->rate & HDMI_AUDIO_FS_96000)
231                         hdmi_dbg(hdmi->dev, "   96000\n");
232                 if(audio->rate & HDMI_AUDIO_FS_176400)
233                         hdmi_dbg(hdmi->dev, "   176400\n");
234                 if(audio->rate & HDMI_AUDIO_FS_192000)
235                         hdmi_dbg(hdmi->dev, "   192000\n");
236                 
237                 hdmi_dbg(hdmi->dev, "Support audio word lenght: \n");
238                 if(audio->rate & HDMI_AUDIO_WORD_LENGTH_16bit)
239                         hdmi_dbg(hdmi->dev, "   16bit\n");
240                 if(audio->rate & HDMI_AUDIO_WORD_LENGTH_20bit)
241                         hdmi_dbg(hdmi->dev, "   20bit\n");
242                 if(audio->rate & HDMI_AUDIO_WORD_LENGTH_24bit)
243                         hdmi_dbg(hdmi->dev, "   24bit\n");
244         }
245         hdmi_dbg(hdmi->dev, "******** Show Sink Info ********\n");
246 }
247
248 /**
249  * hdmi_ouputmode_select - select hdmi transmitter output mode: hdmi or dvi?
250  * @hdmi: handle of hdmi
251  * @edid_ok: get EDID data success or not, HDMI_ERROR_SUCESS means success.
252  */
253 int hdmi_ouputmode_select(struct hdmi *hdmi, int edid_ok)
254 {
255         struct list_head *head = &hdmi->edid.modelist;
256         struct fb_monspecs      *specs = hdmi->edid.specs;
257         struct fb_videomode *modedb = NULL;
258         int i, pixclock;
259         
260         if(edid_ok != HDMI_ERROR_SUCESS) {
261                 dev_err(hdmi->dev, "warning: EDID error, assume sink as HDMI and asume minitor support audio output!!!!");
262                 hdmi->edid.sink_hdmi = 1;
263                 //if edid error,asume monitor support audio output.
264                 hdmi->edid.base_audio_support = 1;
265         }
266
267         if(edid_ok != HDMI_ERROR_SUCESS) {
268                 hdmi->edid.ycbcr444 = 0;
269                 hdmi->edid.ycbcr422 = 0;
270                 hdmi->autoconfig = HDMI_DISABLE;
271         }
272         if(head->next == head) {
273                 dev_info(hdmi->dev, "warning: no CEA video mode parsed from EDID !!!!");
274                 // If EDID get error, list all system supported mode.
275                 // If output mode is set to DVI and EDID is ok, check
276                 // the output timing.
277                 
278                 if(hdmi->edid.sink_hdmi == 0 && specs && specs->modedb_len) {
279                         /* Get max resolution timing */
280                         modedb = &specs->modedb[0];
281                         for (i = 0; i < specs->modedb_len; i++) {
282                                 if(specs->modedb[i].xres > modedb->xres)
283                                         modedb = &specs->modedb[i];
284                                 else if(specs->modedb[i].yres > modedb->yres)
285                                         modedb = &specs->modedb[i];
286                         }
287                         // For some monitor, the max pixclock read from EDID is smaller
288                         // than the clock of max resolution mode supported. We fix it.
289                         pixclock = PICOS2KHZ(modedb->pixclock);
290                         pixclock /= 250;
291                         pixclock *= 250;
292                         pixclock *= 1000;
293                         if(pixclock == 148250000)
294                                 pixclock = 148500000;
295                         if(pixclock > specs->dclkmax)
296                                 specs->dclkmax = pixclock;
297                 }
298                 
299                 for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
300                         if(modedb) {
301                                 if( (hdmi_mode[i].pixclock < specs->dclkmin) || 
302                                         (hdmi_mode[i].pixclock > specs->dclkmax) || 
303                                         (hdmi_mode[i].refresh < specs->vfmin) ||
304                                         (hdmi_mode[i].refresh > specs->vfmax) ||
305                                         (hdmi_mode[i].xres > modedb->xres) ||
306                                         (hdmi_mode[i].yres > modedb->yres) )
307                                 continue;
308                         }
309                         hdmi_add_videomode(&hdmi_mode[i], head);
310                 }
311         }
312         
313         #ifdef HDMI_DEBUG
314         hdmi_show_sink_info(hdmi);
315         #endif
316         return HDMI_ERROR_SUCESS;
317 }
318 /**
319  * hdmi_videomode_compare - compare 2 videomodes
320  * @mode1: first videomode
321  * @mode2: second videomode
322  *
323  * RETURNS:
324  * 1 if mode1 > mode2, 0 if mode1 = mode2, -1 mode1 < mode2
325  */
326 static int hdmi_videomode_compare(const struct fb_videomode *mode1,
327                      const struct fb_videomode *mode2)
328 {
329         if(mode1->xres > mode2->xres)
330                 return 1;
331         else if(mode1->xres == mode2->xres)
332         { 
333                 if(mode1->yres > mode2->yres)
334                         return 1;
335                 else if(mode1->yres == mode2->yres)
336                 {
337                         if(mode1->pixclock > mode2->pixclock)   
338                                 return 1;
339                         else if(mode1->pixclock == mode2->pixclock)
340                         {       
341                                 if(mode1->refresh > mode2->refresh)
342                                         return 1;
343                                 else if(mode1->refresh == mode2->refresh) 
344                                         return 0;
345                         }
346                 }
347         }
348         return -1;              
349 }
350 /**
351  * hdmi_add_videomode: adds videomode entry to modelist
352  * @mode: videomode to add
353  * @head: struct list_head of modelist
354  *
355  * NOTES:
356  * Will only add unmatched mode entries
357  */
358 int hdmi_add_videomode(const struct fb_videomode *mode, struct list_head *head)
359 {
360         struct list_head *pos;
361         struct fb_modelist *modelist, *modelist_new;
362         struct fb_videomode *m;
363         int i, found = 0;
364
365         for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
366     {
367         m =(struct fb_videomode*) &hdmi_mode[i];
368         if (fb_mode_is_equal(m, mode)) {
369                         found = 1;
370                         break;
371                 }
372     }
373
374         if (found) {
375                 list_for_each(pos, head) {
376                         modelist = list_entry(pos, struct fb_modelist, list);
377                         m = &modelist->mode;
378                         if (fb_mode_is_equal(m, mode)) {
379                         // m == mode    
380                                 return 0;
381                         }
382                         else
383                         { 
384                                 if(hdmi_videomode_compare(m, mode) == -1) {
385                                         break;
386                                 }
387                         }
388                 }
389
390                 modelist_new = kmalloc(sizeof(struct fb_modelist),
391                                   GFP_KERNEL);                                  
392                 if (!modelist_new)
393                         return -ENOMEM; 
394                 modelist_new->mode = hdmi_mode[i];
395                 list_add_tail(&modelist_new->list, pos);
396         }
397         
398         return 0;
399 }
400
401 /**
402  * hdmi_videomode_to_vic: transverse video mode to vic
403  * @vmode: videomode to transverse
404  * 
405  */
406 int hdmi_videomode_to_vic(struct fb_videomode *vmode)
407 {
408         unsigned char vic = 0;
409         int i = 0;
410         
411         for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
412         {
413                 if(     vmode->vmode == hdmi_mode[i].vmode &&
414                         vmode->refresh == hdmi_mode[i].refresh &&
415                         vmode->xres == hdmi_mode[i].xres && 
416                         vmode->left_margin == hdmi_mode[i].left_margin &&
417                         vmode->right_margin == hdmi_mode[i].right_margin &&
418                         vmode->upper_margin == hdmi_mode[i].upper_margin &&
419                         vmode->lower_margin == hdmi_mode[i].lower_margin && 
420                         vmode->hsync_len == hdmi_mode[i].hsync_len && 
421                         vmode->vsync_len == hdmi_mode[i].vsync_len)
422                 {
423                         if( (vmode->vmode == FB_VMODE_NONINTERLACED && vmode->yres == hdmi_mode[i].yres) || 
424                                 (vmode->vmode == FB_VMODE_INTERLACED && vmode->yres == hdmi_mode[i].yres/2))
425                         {                                                               
426                                 vic = hdmi_mode[i].flag;
427                                 break;
428                         }
429                 }
430         }
431         return vic;
432 }
433
434 /**
435  * hdmi_vic_to_videomode: transverse vic mode to video mode
436  * @vmode: vic to transverse
437  * 
438  */
439 const struct fb_videomode* hdmi_vic_to_videomode(int vic)
440 {
441         int i;
442         
443         if(vic == 0)
444                 return NULL;
445         
446         for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
447         {
448                 if(hdmi_mode[i].flag == vic)
449                         return &hdmi_mode[i];
450         }
451         return NULL;
452 }
453
454 /**
455  * hdmi_find_best_mode: find the video mode nearest to input vic
456  * @hdmi: 
457  * @vic: input vic
458  * 
459  * NOTES:
460  * If vic is zero, return the high resolution video mode vic.
461  */
462 int hdmi_find_best_mode(struct hdmi* hdmi, int vic)
463 {
464         struct list_head *pos, *head = &hdmi->edid.modelist;
465         struct fb_modelist *modelist;
466         struct fb_videomode *m = NULL;
467         int found = 0;
468         
469         if(vic)
470         {
471                 list_for_each(pos, head) {
472                         modelist = list_entry(pos, struct fb_modelist, list);
473                         m = &modelist->mode;
474                         if(m->flag == vic)
475                         {
476                                 found = 1;      
477                                 break;
478                         }
479                 }
480         }
481         if( (vic == 0 || found == 0) && head->next != head)
482         {
483                 modelist = list_entry(head->next, struct fb_modelist, list);
484                 m = &modelist->mode;
485         }
486         if(m != NULL)
487                 return m->flag;
488         else
489                 return 0;
490 }
491
492 const char *hdmi_get_video_mode_name(unsigned char vic)
493 {
494         int i;
495         
496         for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
497         {
498                 if(vic == hdmi_mode[i].flag)
499                         break;
500         }
501         if(i == ARRAY_SIZE(hdmi_mode))
502                 return NULL;
503         else
504                 return hdmi_mode[i].name;
505 }
506
507 /**
508  * hdmi_switch_fb: switch lcdc mode to required video mode
509  * @hdmi: 
510  * @type:
511  * 
512  * NOTES:
513  * 
514  */
515 int hdmi_switch_fb(struct hdmi *hdmi, int vic)
516 {
517         int rc = 0;
518         struct rk_screen *screen;
519         
520         
521         screen =  kzalloc(sizeof(struct rk_screen), GFP_KERNEL);
522         if(screen == NULL)
523                 return -1;
524         
525         if(hdmi->vic == 0)
526                 hdmi->vic = HDMI_VIDEO_DEFAULT_MODE;
527                 
528
529         rc = hdmi_set_info(screen, hdmi->vic);
530
531         if(rc == 0) {
532                 if(hdmi->set_vif)
533                         hdmi->set_vif(hdmi,screen,0); //turn off vif for jettab
534                 rk_fb_switch_screen(screen, 1, hdmi->lcdc->id);
535                 rk_fb_disp_scale(hdmi->xscale, hdmi->yscale, hdmi->lcdc->id);
536                 if(hdmi->set_vif)
537                         hdmi->set_vif(hdmi,screen,1);
538
539         }
540         
541         kfree(screen);
542         
543         return rc;
544 }
545
546 /**
547  * hdmi_init_video_para: init video_para variable
548  *
549  * NOTES:
550  *This parameters should be modified according to need by user
551  */
552 int hdmi_init_video_para(struct hdmi *hdmi_drv, struct hdmi_video_para *video)
553 {
554         memset(video, 0, sizeof(struct hdmi_video_para));
555         video->vic = hdmi_drv->vic;
556         video->input_mode = VIDEO_INPUT_RGB_YCBCR_444;
557         video->input_color = VIDEO_INPUT_COLOR_RGB;//VIDEO_INPUT_COLOR_YCBCR
558         video->output_mode = hdmi_drv->edid.sink_hdmi;
559         video->format_3d = 0;   /*TODO modify according to EDID if need*/
560         video->pixel_repet = 0;
561         video->color_limit_range = 1; //0:IT Video Format  1:CE Video Format --TODO modify according to EDID
562
563 #ifdef SOURCE_ABOVE_10BIT
564         if (hdmi_drv->edid.deepcolor & HDMI_COLOR_DEPTH_16BIT)
565                 video->color_depth = HDMI_COLOR_DEPTH_16BIT;
566         else if (hdmi_drv->edid.deepcolor & HDMI_COLOR_DEPTH_12BIT)
567                 video->color_depth = HDMI_COLOR_DEPTH_12BIT;
568         else
569 #endif
570         if (hdmi_drv->edid.deepcolor & HDMI_COLOR_DEPTH_10BIT)
571                 video->color_depth = HDMI_COLOR_DEPTH_10BIT;
572         else
573                 video->color_depth = HDMI_COLOR_DEPTH_8BIT;
574
575         if (hdmi_drv->edid.ycbcr444)
576                 video->output_color = VIDEO_OUTPUT_YCBCR444;
577         else if (hdmi_drv->edid.ycbcr422)
578                 video->output_color = VIDEO_OUTPUT_YCBCR422;
579         else
580                 video->output_color = VIDEO_OUTPUT_RGB444;
581
582         /*For DVI, output RGB*/
583         if (hdmi_drv->edid.sink_hdmi == 0)
584                 video->output_color = VIDEO_OUTPUT_RGB444;
585
586         return 0;
587 }
588
589 /**
590  * hdmi_drv_register: init hdmi_drv variable
591  *
592  * NOTES:
593  *
594  */
595 int hdmi_drv_register(struct hdmi *hdmi_drv)
596 {
597         m_hdmi_drv = hdmi_drv;
598         return 0;
599 }
600
601 /**
602  * hdmi_get_status: get hdmi hotplug status
603  * 
604  * NOTES:
605  * 
606  */
607 int hdmi_get_hotplug(void)
608 {
609         if(m_hdmi_drv)
610                 return m_hdmi_drv->hotplug;
611         else
612                 return HDMI_HPD_REMOVED;
613 }