rk3288 hdmi: adjust init overscan para according to the resolution that may only...
[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         /*Init Default Overscan Value: TODO modify the value according to your need adjust value*/
151         switch(vic) {
152         case 16: /*1080p-60Hz*/
153                 screen->overscan.left = 97;
154                 screen->overscan.top = 97;
155                 screen->overscan.right = 97;
156                 screen->overscan.bottom = 97;
157                 break;
158         default:
159                 screen->overscan.left = 96;
160                 screen->overscan.top = 96;
161                 screen->overscan.right = 96;
162                 screen->overscan.bottom = 96;
163                 break;
164         }
165     
166     return 0;
167 }
168
169 static void hdmi_show_sink_info(struct hdmi *hdmi)
170 {
171         struct list_head *pos, *head = &hdmi->edid.modelist;
172         struct fb_modelist *modelist;
173         struct fb_videomode *m;
174         int i;
175         struct hdmi_audio *audio;
176
177         hdmi_dbg(hdmi->dev, "******** Show Sink Info ********\n");
178         hdmi_dbg(hdmi->dev, "Support video mode: \n");
179         list_for_each(pos, head) {
180                 modelist = list_entry(pos, struct fb_modelist, list);
181                 m = &modelist->mode;
182                 hdmi_dbg(hdmi->dev, "   %s.\n", m->name);
183         }
184         
185         for(i = 0; i < hdmi->edid.audio_num; i++)
186         {
187                 audio = &(hdmi->edid.audio[i]);
188                 switch(audio->type)
189                 {
190                         case HDMI_AUDIO_LPCM:
191                                 hdmi_dbg(hdmi->dev, "Support audio type: LPCM\n");
192                                 break;
193                         case HDMI_AUDIO_AC3:
194                                 hdmi_dbg(hdmi->dev, "Support audio type: AC3\n");
195                                 break;
196                         case HDMI_AUDIO_MPEG1:
197                                 hdmi_dbg(hdmi->dev, "Support audio type: MPEG1\n");
198                                 break;
199                         case HDMI_AUDIO_MP3:
200                                 hdmi_dbg(hdmi->dev, "Support audio type: MP3\n");
201                                 break;
202                         case HDMI_AUDIO_MPEG2:
203                                 hdmi_dbg(hdmi->dev, "Support audio type: MPEG2\n");
204                                 break;
205                         case HDMI_AUDIO_AAC_LC:
206                                 hdmi_dbg(hdmi->dev, "Support audio type: AAC\n");
207                                 break;
208                         case HDMI_AUDIO_DTS:
209                                 hdmi_dbg(hdmi->dev, "Support audio type: DTS\n");
210                                 break;
211                         case HDMI_AUDIO_ATARC:
212                                 hdmi_dbg(hdmi->dev, "Support audio type: ATARC\n");
213                                 break;
214                         case HDMI_AUDIO_DSD:
215                                 hdmi_dbg(hdmi->dev, "Support audio type: DSD\n");
216                                 break;
217                         case HDMI_AUDIO_E_AC3:
218                                 hdmi_dbg(hdmi->dev, "Support audio type: E-AC3\n");
219                                 break;
220                         case HDMI_AUDIO_DTS_HD:
221                                 hdmi_dbg(hdmi->dev, "Support audio type: DTS-HD\n");
222                                 break;
223                         case HDMI_AUDIO_MLP:
224                                 hdmi_dbg(hdmi->dev, "Support audio type: MLP\n");
225                                 break;
226                         case HDMI_AUDIO_DST:
227                                 hdmi_dbg(hdmi->dev, "Support audio type: DST\n");
228                                 break;
229                         case HDMI_AUDIO_WMA_PRO:
230                                 hdmi_dbg(hdmi->dev, "Support audio type: WMP-PRO\n");
231                                 break;
232                         default:
233                                 hdmi_dbg(hdmi->dev, "Support audio type: Unkown\n");
234                                 break;
235                 }
236                 
237                 hdmi_dbg(hdmi->dev, "Support audio sample rate: \n");
238                 if(audio->rate & HDMI_AUDIO_FS_32000)
239                         hdmi_dbg(hdmi->dev, "   32000\n");
240                 if(audio->rate & HDMI_AUDIO_FS_44100)
241                         hdmi_dbg(hdmi->dev, "   44100\n");
242                 if(audio->rate & HDMI_AUDIO_FS_48000)
243                         hdmi_dbg(hdmi->dev, "   48000\n");
244                 if(audio->rate & HDMI_AUDIO_FS_88200)
245                         hdmi_dbg(hdmi->dev, "   88200\n");
246                 if(audio->rate & HDMI_AUDIO_FS_96000)
247                         hdmi_dbg(hdmi->dev, "   96000\n");
248                 if(audio->rate & HDMI_AUDIO_FS_176400)
249                         hdmi_dbg(hdmi->dev, "   176400\n");
250                 if(audio->rate & HDMI_AUDIO_FS_192000)
251                         hdmi_dbg(hdmi->dev, "   192000\n");
252                 
253                 hdmi_dbg(hdmi->dev, "Support audio word lenght: \n");
254                 if(audio->rate & HDMI_AUDIO_WORD_LENGTH_16bit)
255                         hdmi_dbg(hdmi->dev, "   16bit\n");
256                 if(audio->rate & HDMI_AUDIO_WORD_LENGTH_20bit)
257                         hdmi_dbg(hdmi->dev, "   20bit\n");
258                 if(audio->rate & HDMI_AUDIO_WORD_LENGTH_24bit)
259                         hdmi_dbg(hdmi->dev, "   24bit\n");
260         }
261         hdmi_dbg(hdmi->dev, "******** Show Sink Info ********\n");
262 }
263
264 /**
265  * hdmi_ouputmode_select - select hdmi transmitter output mode: hdmi or dvi?
266  * @hdmi: handle of hdmi
267  * @edid_ok: get EDID data success or not, HDMI_ERROR_SUCESS means success.
268  */
269 int hdmi_ouputmode_select(struct hdmi *hdmi, int edid_ok)
270 {
271         struct list_head *head = &hdmi->edid.modelist;
272         struct fb_monspecs      *specs = hdmi->edid.specs;
273         struct fb_videomode *modedb = NULL;
274         int i, pixclock;
275         
276         if(edid_ok != HDMI_ERROR_SUCESS) {
277                 dev_err(hdmi->dev, "warning: EDID error, assume sink as HDMI and asume minitor support audio output!!!!");
278                 hdmi->edid.sink_hdmi = 1;
279                 //if edid error,asume monitor support audio output.
280                 hdmi->edid.base_audio_support = 1;
281         }
282
283         if(edid_ok != HDMI_ERROR_SUCESS) {
284                 hdmi->edid.ycbcr444 = 0;
285                 hdmi->edid.ycbcr422 = 0;
286                 hdmi->autoconfig = HDMI_DISABLE;
287         }
288         if(head->next == head) {
289                 dev_info(hdmi->dev, "warning: no CEA video mode parsed from EDID !!!!");
290                 // If EDID get error, list all system supported mode.
291                 // If output mode is set to DVI and EDID is ok, check
292                 // the output timing.
293                 
294                 if(hdmi->edid.sink_hdmi == 0 && specs && specs->modedb_len) {
295                         /* Get max resolution timing */
296                         modedb = &specs->modedb[0];
297                         for (i = 0; i < specs->modedb_len; i++) {
298                                 if(specs->modedb[i].xres > modedb->xres)
299                                         modedb = &specs->modedb[i];
300                                 else if(specs->modedb[i].yres > modedb->yres)
301                                         modedb = &specs->modedb[i];
302                         }
303                         // For some monitor, the max pixclock read from EDID is smaller
304                         // than the clock of max resolution mode supported. We fix it.
305                         pixclock = PICOS2KHZ(modedb->pixclock);
306                         pixclock /= 250;
307                         pixclock *= 250;
308                         pixclock *= 1000;
309                         if(pixclock == 148250000)
310                                 pixclock = 148500000;
311                         if(pixclock > specs->dclkmax)
312                                 specs->dclkmax = pixclock;
313                 }
314                 
315                 for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
316                         if(modedb) {
317                                 if( (hdmi_mode[i].pixclock < specs->dclkmin) || 
318                                         (hdmi_mode[i].pixclock > specs->dclkmax) || 
319                                         (hdmi_mode[i].refresh < specs->vfmin) ||
320                                         (hdmi_mode[i].refresh > specs->vfmax) ||
321                                         (hdmi_mode[i].xres > modedb->xres) ||
322                                         (hdmi_mode[i].yres > modedb->yres) )
323                                 continue;
324                         }
325                         hdmi_add_videomode(&hdmi_mode[i], head);
326                 }
327         }
328         
329         #ifdef HDMI_DEBUG
330         hdmi_show_sink_info(hdmi);
331         #endif
332         return HDMI_ERROR_SUCESS;
333 }
334 /**
335  * hdmi_videomode_compare - compare 2 videomodes
336  * @mode1: first videomode
337  * @mode2: second videomode
338  *
339  * RETURNS:
340  * 1 if mode1 > mode2, 0 if mode1 = mode2, -1 mode1 < mode2
341  */
342 static int hdmi_videomode_compare(const struct fb_videomode *mode1,
343                      const struct fb_videomode *mode2)
344 {
345         if(mode1->xres > mode2->xres)
346                 return 1;
347         else if(mode1->xres == mode2->xres)
348         { 
349                 if(mode1->yres > mode2->yres)
350                         return 1;
351                 else if(mode1->yres == mode2->yres)
352                 {
353                         if(mode1->pixclock > mode2->pixclock)   
354                                 return 1;
355                         else if(mode1->pixclock == mode2->pixclock)
356                         {       
357                                 if(mode1->refresh > mode2->refresh)
358                                         return 1;
359                                 else if(mode1->refresh == mode2->refresh) 
360                                         return 0;
361                         }
362                 }
363         }
364         return -1;              
365 }
366 /**
367  * hdmi_add_videomode: adds videomode entry to modelist
368  * @mode: videomode to add
369  * @head: struct list_head of modelist
370  *
371  * NOTES:
372  * Will only add unmatched mode entries
373  */
374 int hdmi_add_videomode(const struct fb_videomode *mode, struct list_head *head)
375 {
376         struct list_head *pos;
377         struct fb_modelist *modelist, *modelist_new;
378         struct fb_videomode *m;
379         int i, found = 0;
380
381         for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
382     {
383         m =(struct fb_videomode*) &hdmi_mode[i];
384         if (fb_mode_is_equal(m, mode)) {
385                         found = 1;
386                         break;
387                 }
388     }
389
390         if (found) {
391                 list_for_each(pos, head) {
392                         modelist = list_entry(pos, struct fb_modelist, list);
393                         m = &modelist->mode;
394                         if (fb_mode_is_equal(m, mode)) {
395                         // m == mode    
396                                 return 0;
397                         }
398                         else
399                         { 
400                                 if(hdmi_videomode_compare(m, mode) == -1) {
401                                         break;
402                                 }
403                         }
404                 }
405
406                 modelist_new = kmalloc(sizeof(struct fb_modelist),
407                                   GFP_KERNEL);                                  
408                 if (!modelist_new)
409                         return -ENOMEM; 
410                 modelist_new->mode = hdmi_mode[i];
411                 list_add_tail(&modelist_new->list, pos);
412         }
413         
414         return 0;
415 }
416
417 /**
418  * hdmi_videomode_to_vic: transverse video mode to vic
419  * @vmode: videomode to transverse
420  * 
421  */
422 int hdmi_videomode_to_vic(struct fb_videomode *vmode)
423 {
424         unsigned char vic = 0;
425         int i = 0;
426         
427         for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
428         {
429                 if(     vmode->vmode == hdmi_mode[i].vmode &&
430                         vmode->refresh == hdmi_mode[i].refresh &&
431                         vmode->xres == hdmi_mode[i].xres && 
432                         vmode->left_margin == hdmi_mode[i].left_margin &&
433                         vmode->right_margin == hdmi_mode[i].right_margin &&
434                         vmode->upper_margin == hdmi_mode[i].upper_margin &&
435                         vmode->lower_margin == hdmi_mode[i].lower_margin && 
436                         vmode->hsync_len == hdmi_mode[i].hsync_len && 
437                         vmode->vsync_len == hdmi_mode[i].vsync_len)
438                 {
439                         if( (vmode->vmode == FB_VMODE_NONINTERLACED && vmode->yres == hdmi_mode[i].yres) || 
440                                 (vmode->vmode == FB_VMODE_INTERLACED && vmode->yres == hdmi_mode[i].yres/2))
441                         {                                                               
442                                 vic = hdmi_mode[i].flag;
443                                 break;
444                         }
445                 }
446         }
447         return vic;
448 }
449
450 /**
451  * hdmi_vic_to_videomode: transverse vic mode to video mode
452  * @vmode: vic to transverse
453  * 
454  */
455 const struct fb_videomode* hdmi_vic_to_videomode(int vic)
456 {
457         int i;
458         
459         if(vic == 0)
460                 return NULL;
461         
462         for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
463         {
464                 if(hdmi_mode[i].flag == vic)
465                         return &hdmi_mode[i];
466         }
467         return NULL;
468 }
469
470 /**
471  * hdmi_find_best_mode: find the video mode nearest to input vic
472  * @hdmi: 
473  * @vic: input vic
474  * 
475  * NOTES:
476  * If vic is zero, return the high resolution video mode vic.
477  */
478 int hdmi_find_best_mode(struct hdmi* hdmi, int vic)
479 {
480         struct list_head *pos, *head = &hdmi->edid.modelist;
481         struct fb_modelist *modelist;
482         struct fb_videomode *m = NULL;
483         int found = 0;
484         
485         if(vic)
486         {
487                 list_for_each(pos, head) {
488                         modelist = list_entry(pos, struct fb_modelist, list);
489                         m = &modelist->mode;
490                         if(m->flag == vic)
491                         {
492                                 found = 1;      
493                                 break;
494                         }
495                 }
496         }
497         if( (vic == 0 || found == 0) && head->next != head)
498         {
499                 modelist = list_entry(head->next, struct fb_modelist, list);
500                 m = &modelist->mode;
501         }
502         if(m != NULL)
503                 return m->flag;
504         else
505                 return 0;
506 }
507
508 const char *hdmi_get_video_mode_name(unsigned char vic)
509 {
510         int i;
511         
512         for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
513         {
514                 if(vic == hdmi_mode[i].flag)
515                         break;
516         }
517         if(i == ARRAY_SIZE(hdmi_mode))
518                 return NULL;
519         else
520                 return hdmi_mode[i].name;
521 }
522
523 /**
524  * hdmi_switch_fb: switch lcdc mode to required video mode
525  * @hdmi: 
526  * @type:
527  * 
528  * NOTES:
529  * 
530  */
531 int hdmi_switch_fb(struct hdmi *hdmi, int vic)
532 {
533         int rc = 0;
534         struct rk_screen *screen;
535         
536         
537         screen =  kzalloc(sizeof(struct rk_screen), GFP_KERNEL);
538         if(screen == NULL)
539                 return -1;
540         
541         if(hdmi->vic == 0)
542                 hdmi->vic = HDMI_VIDEO_DEFAULT_MODE;
543                 
544
545         rc = hdmi_set_info(screen, hdmi->vic);
546
547         if(rc == 0) {
548                 if(hdmi->set_vif)
549                         hdmi->set_vif(hdmi,screen,0); //turn off vif for jettab
550                 rk_fb_switch_screen(screen, 1, hdmi->lcdc->id);
551                 rk_fb_disp_scale(hdmi->xscale, hdmi->yscale, hdmi->lcdc->id);
552                 if(hdmi->set_vif)
553                         hdmi->set_vif(hdmi,screen,1);
554
555         }
556         
557         kfree(screen);
558         
559         return rc;
560 }
561
562 /**
563  * hdmi_init_video_para: init video_para variable
564  *
565  * NOTES:
566  *This parameters should be modified according to need by user
567  */
568 int hdmi_init_video_para(struct hdmi *hdmi_drv, struct hdmi_video_para *video)
569 {
570         memset(video, 0, sizeof(struct hdmi_video_para));
571         video->vic = hdmi_drv->vic;
572         video->input_mode = VIDEO_INPUT_RGB_YCBCR_444;
573         video->input_color = VIDEO_INPUT_COLOR_RGB;//VIDEO_INPUT_COLOR_YCBCR
574         video->output_mode = hdmi_drv->edid.sink_hdmi;
575         video->format_3d = 0;   /*TODO modify according to EDID if need*/
576         video->pixel_repet = 0;
577         video->color_limit_range = 1; //0:IT Video Format  1:CE Video Format --TODO modify according to EDID
578
579 #ifdef SOURCE_ABOVE_10BIT
580         if (hdmi_drv->edid.deepcolor & HDMI_COLOR_DEPTH_16BIT)
581                 video->color_depth = HDMI_COLOR_DEPTH_16BIT;
582         else if (hdmi_drv->edid.deepcolor & HDMI_COLOR_DEPTH_12BIT)
583                 video->color_depth = HDMI_COLOR_DEPTH_12BIT;
584         else
585 #endif
586         if (hdmi_drv->edid.deepcolor & HDMI_COLOR_DEPTH_10BIT)
587                 video->color_depth = HDMI_COLOR_DEPTH_10BIT;
588         else
589                 video->color_depth = HDMI_COLOR_DEPTH_8BIT;
590
591         if (hdmi_drv->edid.ycbcr444)
592                 video->output_color = VIDEO_OUTPUT_YCBCR444;
593         else if (hdmi_drv->edid.ycbcr422)
594                 video->output_color = VIDEO_OUTPUT_YCBCR422;
595         else
596                 video->output_color = VIDEO_OUTPUT_RGB444;
597
598         /*For DVI, output RGB*/
599         if (hdmi_drv->edid.sink_hdmi == 0)
600                 video->output_color = VIDEO_OUTPUT_RGB444;
601
602         return 0;
603 }
604
605 /**
606  * hdmi_drv_register: init hdmi_drv variable
607  *
608  * NOTES:
609  *
610  */
611 int hdmi_drv_register(struct hdmi *hdmi_drv)
612 {
613         m_hdmi_drv = hdmi_drv;
614         return 0;
615 }
616
617 /**
618  * hdmi_get_status: get hdmi hotplug status
619  * 
620  * NOTES:
621  * 
622  */
623 int hdmi_get_hotplug(void)
624 {
625         if(m_hdmi_drv)
626                 return m_hdmi_drv->hotplug;
627         else
628                 return HDMI_HPD_REMOVED;
629 }