adc640596a9a31a471424a3f8a0e8efc87b31bd5
[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 {       "4096x2160p@24Hz",      24,             4096,   2160,   297000000,      296,    1020,   72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              98      },
67
68 };
69
70 void hdmi_init_lcdc(struct rk_screen *screen, struct rk29lcd_info *lcd_info)
71 {
72         hdmi_set_info(screen, HDMI_VIDEO_DEFAULT_MODE);
73 }
74
75 int hdmi_set_info(struct rk_screen *screen, unsigned int vic)
76 {
77     int i;
78     
79     if(screen == NULL)
80         return -1;
81     
82     if(vic == 0)
83         vic = HDMI_VIDEO_DEFAULT_MODE;
84         
85     for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
86     {
87         if(hdmi_mode[i].flag == vic)
88                 break;
89     }
90     if(i == ARRAY_SIZE(hdmi_mode))
91         return -1;
92     
93     memset(screen, 0, sizeof(struct rk_screen));
94     
95     /* screen type & face */
96     screen->type = OUT_TYPE;
97     screen->face = OUT_FACE;
98
99     /* Screen size */
100     screen->mode.xres = hdmi_mode[i].xres;
101     screen->mode.yres = hdmi_mode[i].yres;
102     
103     /* Timing */
104     screen->mode.pixclock = hdmi_mode[i].pixclock;
105     screen->mode.refresh = hdmi_mode[i].refresh;
106         //screen->lcdc_aclk = LCD_ACLK;
107         screen->mode.left_margin = hdmi_mode[i].left_margin;
108         screen->mode.right_margin = hdmi_mode[i].right_margin;
109         screen->mode.hsync_len = hdmi_mode[i].hsync_len;
110         screen->mode.upper_margin = hdmi_mode[i].upper_margin;
111         screen->mode.lower_margin = hdmi_mode[i].lower_margin;
112         screen->mode.vsync_len = hdmi_mode[i].vsync_len;
113         screen->hdmi_resolution = hdmi_mode[i].flag;
114
115         /* Pin polarity */
116 #if defined(CONFIG_HDMI_RK616) && !defined(CONFIG_ARCH_RK3026)
117         screen->pin_hsync = 0;
118         screen->pin_vsync = 0;
119 #else 
120         screen->pin_hsync = 0;
121         if(FB_SYNC_HOR_HIGH_ACT & hdmi_mode[i].sync)
122                 screen->pin_hsync = 1;
123         else
124                 screen->pin_hsync = 0;
125         if(FB_SYNC_VERT_HIGH_ACT & hdmi_mode[i].sync)
126                 screen->pin_vsync = 1;
127         else
128                 screen->pin_vsync = 0;
129 #endif
130         screen->pin_den = 0;
131         screen->pin_dclk = DCLK_POL;
132
133         /* Swap rule */
134     screen->swap_rb = SWAP_RB;
135     screen->swap_rg = 0;
136     screen->swap_gb = 0;
137     screen->swap_delta = 0;
138     screen->swap_dumy = 0;
139
140     /* Operation function*/
141     screen->init = NULL;
142     screen->standby = NULL;
143     
144     return 0;
145 }
146
147 static void hdmi_show_sink_info(struct hdmi *hdmi)
148 {
149         struct list_head *pos, *head = &hdmi->edid.modelist;
150         struct fb_modelist *modelist;
151         struct fb_videomode *m;
152         int i;
153         struct hdmi_audio *audio;
154
155         hdmi_dbg(hdmi->dev, "******** Show Sink Info ********\n");
156         hdmi_dbg(hdmi->dev, "Support video mode: \n");
157         list_for_each(pos, head) {
158                 modelist = list_entry(pos, struct fb_modelist, list);
159                 m = &modelist->mode;
160                 hdmi_dbg(hdmi->dev, "   %s.\n", m->name);
161         }
162         
163         for(i = 0; i < hdmi->edid.audio_num; i++)
164         {
165                 audio = &(hdmi->edid.audio[i]);
166                 switch(audio->type)
167                 {
168                         case HDMI_AUDIO_LPCM:
169                                 hdmi_dbg(hdmi->dev, "Support audio type: LPCM\n");
170                                 break;
171                         case HDMI_AUDIO_AC3:
172                                 hdmi_dbg(hdmi->dev, "Support audio type: AC3\n");
173                                 break;
174                         case HDMI_AUDIO_MPEG1:
175                                 hdmi_dbg(hdmi->dev, "Support audio type: MPEG1\n");
176                                 break;
177                         case HDMI_AUDIO_MP3:
178                                 hdmi_dbg(hdmi->dev, "Support audio type: MP3\n");
179                                 break;
180                         case HDMI_AUDIO_MPEG2:
181                                 hdmi_dbg(hdmi->dev, "Support audio type: MPEG2\n");
182                                 break;
183                         case HDMI_AUDIO_AAC_LC:
184                                 hdmi_dbg(hdmi->dev, "Support audio type: AAC\n");
185                                 break;
186                         case HDMI_AUDIO_DTS:
187                                 hdmi_dbg(hdmi->dev, "Support audio type: DTS\n");
188                                 break;
189                         case HDMI_AUDIO_ATARC:
190                                 hdmi_dbg(hdmi->dev, "Support audio type: ATARC\n");
191                                 break;
192                         case HDMI_AUDIO_DSD:
193                                 hdmi_dbg(hdmi->dev, "Support audio type: DSD\n");
194                                 break;
195                         case HDMI_AUDIO_E_AC3:
196                                 hdmi_dbg(hdmi->dev, "Support audio type: E-AC3\n");
197                                 break;
198                         case HDMI_AUDIO_DTS_HD:
199                                 hdmi_dbg(hdmi->dev, "Support audio type: DTS-HD\n");
200                                 break;
201                         case HDMI_AUDIO_MLP:
202                                 hdmi_dbg(hdmi->dev, "Support audio type: MLP\n");
203                                 break;
204                         case HDMI_AUDIO_DST:
205                                 hdmi_dbg(hdmi->dev, "Support audio type: DST\n");
206                                 break;
207                         case HDMI_AUDIO_WMA_PRO:
208                                 hdmi_dbg(hdmi->dev, "Support audio type: WMP-PRO\n");
209                                 break;
210                         default:
211                                 hdmi_dbg(hdmi->dev, "Support audio type: Unkown\n");
212                                 break;
213                 }
214                 
215                 hdmi_dbg(hdmi->dev, "Support audio sample rate: \n");
216                 if(audio->rate & HDMI_AUDIO_FS_32000)
217                         hdmi_dbg(hdmi->dev, "   32000\n");
218                 if(audio->rate & HDMI_AUDIO_FS_44100)
219                         hdmi_dbg(hdmi->dev, "   44100\n");
220                 if(audio->rate & HDMI_AUDIO_FS_48000)
221                         hdmi_dbg(hdmi->dev, "   48000\n");
222                 if(audio->rate & HDMI_AUDIO_FS_88200)
223                         hdmi_dbg(hdmi->dev, "   88200\n");
224                 if(audio->rate & HDMI_AUDIO_FS_96000)
225                         hdmi_dbg(hdmi->dev, "   96000\n");
226                 if(audio->rate & HDMI_AUDIO_FS_176400)
227                         hdmi_dbg(hdmi->dev, "   176400\n");
228                 if(audio->rate & HDMI_AUDIO_FS_192000)
229                         hdmi_dbg(hdmi->dev, "   192000\n");
230                 
231                 hdmi_dbg(hdmi->dev, "Support audio word lenght: \n");
232                 if(audio->rate & HDMI_AUDIO_WORD_LENGTH_16bit)
233                         hdmi_dbg(hdmi->dev, "   16bit\n");
234                 if(audio->rate & HDMI_AUDIO_WORD_LENGTH_20bit)
235                         hdmi_dbg(hdmi->dev, "   20bit\n");
236                 if(audio->rate & HDMI_AUDIO_WORD_LENGTH_24bit)
237                         hdmi_dbg(hdmi->dev, "   24bit\n");
238         }
239         hdmi_dbg(hdmi->dev, "******** Show Sink Info ********\n");
240 }
241
242 /**
243  * hdmi_ouputmode_select - select hdmi transmitter output mode: hdmi or dvi?
244  * @hdmi: handle of hdmi
245  * @edid_ok: get EDID data success or not, HDMI_ERROR_SUCESS means success.
246  */
247 int hdmi_ouputmode_select(struct hdmi *hdmi, int edid_ok)
248 {
249         struct list_head *head = &hdmi->edid.modelist;
250         struct fb_monspecs      *specs = hdmi->edid.specs;
251         struct fb_videomode *modedb = NULL;
252         int i, pixclock;
253         
254         if(edid_ok != HDMI_ERROR_SUCESS) {
255                 dev_err(hdmi->dev, "warning: EDID error, assume sink as HDMI and asume minitor support audio output!!!!");
256                 hdmi->edid.sink_hdmi = 1;
257                 //if edid error,asume monitor support audio output.
258                 hdmi->edid.base_audio_support = 1;
259         }
260
261         if(edid_ok != HDMI_ERROR_SUCESS) {
262                 hdmi->edid.ycbcr444 = 0;
263                 hdmi->edid.ycbcr422 = 0;
264                 hdmi->autoconfig = HDMI_DISABLE;
265         }
266         if(head->next == head) {
267                 dev_info(hdmi->dev, "warning: no CEA video mode parsed from EDID !!!!");
268                 // If EDID get error, list all system supported mode.
269                 // If output mode is set to DVI and EDID is ok, check
270                 // the output timing.
271                 
272                 if(hdmi->edid.sink_hdmi == 0 && specs && specs->modedb_len) {
273                         /* Get max resolution timing */
274                         modedb = &specs->modedb[0];
275                         for (i = 0; i < specs->modedb_len; i++) {
276                                 if(specs->modedb[i].xres > modedb->xres)
277                                         modedb = &specs->modedb[i];
278                                 else if(specs->modedb[i].yres > modedb->yres)
279                                         modedb = &specs->modedb[i];
280                         }
281                         // For some monitor, the max pixclock read from EDID is smaller
282                         // than the clock of max resolution mode supported. We fix it.
283                         pixclock = PICOS2KHZ(modedb->pixclock);
284                         pixclock /= 250;
285                         pixclock *= 250;
286                         pixclock *= 1000;
287                         if(pixclock == 148250000)
288                                 pixclock = 148500000;
289                         if(pixclock > specs->dclkmax)
290                                 specs->dclkmax = pixclock;
291                 }
292                 
293                 for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
294                         if(modedb) {
295                                 if( (hdmi_mode[i].pixclock < specs->dclkmin) || 
296                                         (hdmi_mode[i].pixclock > specs->dclkmax) || 
297                                         (hdmi_mode[i].refresh < specs->vfmin) ||
298                                         (hdmi_mode[i].refresh > specs->vfmax) ||
299                                         (hdmi_mode[i].xres > modedb->xres) ||
300                                         (hdmi_mode[i].yres > modedb->yres) )
301                                 continue;
302                         }
303                         hdmi_add_videomode(&hdmi_mode[i], head);
304                 }
305         }
306         
307         #ifdef HDMI_DEBUG
308         hdmi_show_sink_info(hdmi);
309         #endif
310         return HDMI_ERROR_SUCESS;
311 }
312 /**
313  * hdmi_videomode_compare - compare 2 videomodes
314  * @mode1: first videomode
315  * @mode2: second videomode
316  *
317  * RETURNS:
318  * 1 if mode1 > mode2, 0 if mode1 = mode2, -1 mode1 < mode2
319  */
320 static int hdmi_videomode_compare(const struct fb_videomode *mode1,
321                      const struct fb_videomode *mode2)
322 {
323         if(mode1->xres > mode2->xres)
324                 return 1;
325         else if(mode1->xres == mode2->xres)
326         { 
327                 if(mode1->yres > mode2->yres)
328                         return 1;
329                 else if(mode1->yres == mode2->yres)
330                 {
331                         if(mode1->pixclock > mode2->pixclock)   
332                                 return 1;
333                         else if(mode1->pixclock == mode2->pixclock)
334                         {       
335                                 if(mode1->refresh > mode2->refresh)
336                                         return 1;
337                                 else if(mode1->refresh == mode2->refresh) 
338                                         return 0;
339                         }
340                 }
341         }
342         return -1;              
343 }
344 /**
345  * hdmi_add_videomode: adds videomode entry to modelist
346  * @mode: videomode to add
347  * @head: struct list_head of modelist
348  *
349  * NOTES:
350  * Will only add unmatched mode entries
351  */
352 int hdmi_add_videomode(const struct fb_videomode *mode, struct list_head *head)
353 {
354         struct list_head *pos;
355         struct fb_modelist *modelist, *modelist_new;
356         struct fb_videomode *m;
357         int i, found = 0;
358
359         for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
360     {
361         m =(struct fb_videomode*) &hdmi_mode[i];
362         if (fb_mode_is_equal(m, mode)) {
363                         found = 1;
364                         break;
365                 }
366     }
367
368         if (found) {
369                 list_for_each(pos, head) {
370                         modelist = list_entry(pos, struct fb_modelist, list);
371                         m = &modelist->mode;
372                         if (fb_mode_is_equal(m, mode)) {
373                         // m == mode    
374                                 return 0;
375                         }
376                         else
377                         { 
378                                 if(hdmi_videomode_compare(m, mode) == -1) {
379                                         break;
380                                 }
381                         }
382                 }
383
384                 modelist_new = kmalloc(sizeof(struct fb_modelist),
385                                   GFP_KERNEL);                                  
386                 if (!modelist_new)
387                         return -ENOMEM; 
388                 modelist_new->mode = hdmi_mode[i];
389                 list_add_tail(&modelist_new->list, pos);
390         }
391         
392         return 0;
393 }
394
395 /**
396  * hdmi_videomode_to_vic: transverse video mode to vic
397  * @vmode: videomode to transverse
398  * 
399  */
400 int hdmi_videomode_to_vic(struct fb_videomode *vmode)
401 {
402         unsigned char vic = 0;
403         int i = 0;
404         
405         for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
406         {
407                 if(     vmode->vmode == hdmi_mode[i].vmode &&
408                         vmode->refresh == hdmi_mode[i].refresh &&
409                         vmode->xres == hdmi_mode[i].xres && 
410                         vmode->left_margin == hdmi_mode[i].left_margin &&
411                         vmode->right_margin == hdmi_mode[i].right_margin &&
412                         vmode->upper_margin == hdmi_mode[i].upper_margin &&
413                         vmode->lower_margin == hdmi_mode[i].lower_margin && 
414                         vmode->hsync_len == hdmi_mode[i].hsync_len && 
415                         vmode->vsync_len == hdmi_mode[i].vsync_len)
416                 {
417                         if( (vmode->vmode == FB_VMODE_NONINTERLACED && vmode->yres == hdmi_mode[i].yres) || 
418                                 (vmode->vmode == FB_VMODE_INTERLACED && vmode->yres == hdmi_mode[i].yres/2))
419                         {                                                               
420                                 vic = hdmi_mode[i].flag;
421                                 break;
422                         }
423                 }
424         }
425         return vic;
426 }
427
428 /**
429  * hdmi_vic_to_videomode: transverse vic mode to video mode
430  * @vmode: vic to transverse
431  * 
432  */
433 const struct fb_videomode* hdmi_vic_to_videomode(int vic)
434 {
435         int i;
436         
437         if(vic == 0)
438                 return NULL;
439         
440         for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
441         {
442                 if(hdmi_mode[i].flag == vic)
443                         return &hdmi_mode[i];
444         }
445         return NULL;
446 }
447
448 /**
449  * hdmi_find_best_mode: find the video mode nearest to input vic
450  * @hdmi: 
451  * @vic: input vic
452  * 
453  * NOTES:
454  * If vic is zero, return the high resolution video mode vic.
455  */
456 int hdmi_find_best_mode(struct hdmi* hdmi, int vic)
457 {
458         struct list_head *pos, *head = &hdmi->edid.modelist;
459         struct fb_modelist *modelist;
460         struct fb_videomode *m = NULL;
461         int found = 0;
462         
463         if(vic)
464         {
465                 list_for_each(pos, head) {
466                         modelist = list_entry(pos, struct fb_modelist, list);
467                         m = &modelist->mode;
468                         if(m->flag == vic)
469                         {
470                                 found = 1;      
471                                 break;
472                         }
473                 }
474         }
475         if( (vic == 0 || found == 0) && head->next != head)
476         {
477                 modelist = list_entry(head->next, struct fb_modelist, list);
478                 m = &modelist->mode;
479         }
480         if(m != NULL)
481                 return m->flag;
482         else
483                 return 0;
484 }
485
486 const char *hdmi_get_video_mode_name(unsigned char vic)
487 {
488         int i;
489         
490         for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
491         {
492                 if(vic == hdmi_mode[i].flag)
493                         break;
494         }
495         if(i == ARRAY_SIZE(hdmi_mode))
496                 return NULL;
497         else
498                 return hdmi_mode[i].name;
499 }
500
501 /**
502  * hdmi_switch_fb: switch lcdc mode to required video mode
503  * @hdmi: 
504  * @type:
505  * 
506  * NOTES:
507  * 
508  */
509 int hdmi_switch_fb(struct hdmi *hdmi, int vic)
510 {
511         int rc = 0;
512         struct rk_screen *screen;
513         
514         
515         screen =  kzalloc(sizeof(struct rk_screen), GFP_KERNEL);
516         if(screen == NULL)
517                 return -1;
518         
519         if(hdmi->vic == 0)
520                 hdmi->vic = HDMI_VIDEO_DEFAULT_MODE;
521                 
522
523         rc = hdmi_set_info(screen, hdmi->vic);
524
525         if(rc == 0) {
526                 if(hdmi->set_vif)
527                         hdmi->set_vif(hdmi,screen,0); //turn off vif for jettab
528                 rk_fb_switch_screen(screen, 1, hdmi->lcdc->id);
529                 rk_fb_disp_scale(hdmi->xscale, hdmi->yscale, hdmi->lcdc->id);
530                 if(hdmi->set_vif)
531                         hdmi->set_vif(hdmi,screen,1);
532
533         }
534         
535         kfree(screen);
536         
537         return rc;
538 }
539
540 /**
541  * hdmi_drv_register: init hdmi_drv variable
542  *
543  * NOTES:
544  *
545  */
546 int hdmi_drv_register(struct hdmi *hdmi_drv)
547 {
548         m_hdmi_drv = hdmi_drv;
549         return 0;
550 }
551
552 /**
553  * hdmi_get_status: get hdmi hotplug status
554  * 
555  * NOTES:
556  * 
557  */
558 int hdmi_get_hotplug(void)
559 {
560         if(m_hdmi_drv)
561                 return m_hdmi_drv->hotplug;
562         else
563                 return HDMI_HPD_REMOVED;
564 }