9e7b8761c88e10408158ca3c0c01a11580d6e198
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / hdmi / rockchip-hdmi-lcdc.c
1 #include "rockchip-hdmi.h"
2
3 static const struct hdmi_video_timing hdmi_mode[] = {
4 /*              name                    refresh xres    yres    pixclock        h_bp    h_fp    v_bp    v_fp    h_pw    v_pw                    polariry                        PorI    flag            vic             2ndvic          pixelrepeat     interface */
5
6         { {     "720x480i@60Hz",        60,     720,    480,    27000000,       57,     19,     15,     4,      62,     3,                      0,                              1,      0       },      6,      HDMI_720X480I_60HZ_16_9,        2,      OUT_P888},
7         { {     "720x576i@50Hz",        50,     720,    576,    27000000,       69,     12,     19,     2,      63,     3,                      0,                              1,      0       },      21,     HDMI_720X576I_50HZ_16_9,        2,      OUT_P888},
8         { {     "720x480p@60Hz",        60,     720,    480,    27000000,       60,     16,     30,     9,      62,     6,                      0,                              0,      0       },      2,      HDMI_720X480P_60HZ_16_9,        1,      OUT_P888},
9         { {     "720x576p@50Hz",        50,     720,    576,    27000000,       68,     12,     39,     5,      64,     5,                      0,                              0,      0       },      17,     HDMI_720X576P_50HZ_16_9,        1,      OUT_P888},
10         { {     "1280x720p@24Hz",       24,     1280,   720,    59400000,       220,    1760,   20,     5,      40,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      60,     HDMI_1280X720P_24HZ_4_3,        1,      OUT_P888},
11         { {     "1280x720p@25Hz",       25,     1280,   720,    74250000,       220,    2420,   20,     5,      40,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      61,     HDMI_1280X720P_25HZ_4_3,        1,      OUT_P888},
12         { {     "1280x720p@30Hz",       30,     1280,   720,    74250000,       220,    1760,   20,     5,      40,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      62,     HDMI_1280X720P_30HZ_4_3,        1,      OUT_P888},
13         { {     "1280x720p@50Hz",       50,     1280,   720,    74250000,       220,    440,    20,     5,      40,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      19,     HDMI_1280X720P_50HZ_4_3,        1,      OUT_P888},
14         { {     "1280x720p@60Hz",       60,     1280,   720,    74250000,       220,    110,    20,     5,      40,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      4,      HDMI_1280X720P_60HZ_4_3,        1,      OUT_P888},
15         { {     "1920x1080i@50Hz",      50,     1920,   1080,   74250000,       148,    528,    15,     2,      44,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   1,      0       },      20,     0,                              1,      OUT_P888},
16         { {     "1920x1080i@60Hz",      60,     1920,   1080,   74250000,       148,    88,     15,     2,      44,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   1,      0       },      5,      0,                              1,      OUT_P888},
17         { {     "1920x1080p@24Hz",      24,     1920,   1080,   74250000,       148,    638,    36,     4,      44,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      32,     HDMI_1920X1080P_24HZ_4_3,       1,      OUT_P888},
18         { {     "1920x1080p@25Hz",      25,     1920,   1080,   74250000,       148,    528,    36,     4,      44,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      33,     HDMI_1920X1080P_25HZ_4_3,       1,      OUT_P888},
19         { {     "1920x1080p@30Hz",      30,     1920,   1080,   74250000,       148,    88,     36,     4,      44,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      34,     HDMI_1920X1080P_30HZ_4_3,       1,      OUT_P888},
20         { {     "1920x1080p@50Hz",      50,     1920,   1080,   148500000,      148,    528,    36,     4,      44,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      31,     HDMI_1920X1080P_50HZ_4_3,       1,      OUT_P888},
21         { {     "1920x1080p@60Hz",      60,     1920,   1080,   148500000,      148,    88,     36,     4,      44,     5,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      16,     HDMI_1920X1080P_60HZ_4_3,       1,      OUT_P888},
22         { {     "3840x2160p@24Hz",      24,     3840,   2160,   297000000,      296,    1276,   72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      93,     HDMI_3840X2160P_24HZ_4_3,       1,      OUT_P888},
23         { {     "3840x2160p@25Hz",      25,     3840,   2160,   297000000,      296,    1056,   72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      94,     HDMI_3840X2160P_25HZ_4_3,       1,      OUT_P888},
24         { {     "3840x2160p@30Hz",      30,     3840,   2160,   297000000,      296,    176,    72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      95,     HDMI_3840X2160P_30HZ_4_3,       1,      OUT_P888},
25         { {     "4096x2160p@24Hz",      24,     4096,   2160,   297000000,      296,    1020,   72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      98,     0,                              1,      OUT_P888},
26         { {     "4096x2160p@25Hz",      25,     4096,   2160,   297000000,      128,    968,    72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      99,     0,                              1,      OUT_P888},
27         { {     "4096x2160p@30Hz",      30,     4096,   2160,   297000000,      128,    88,     72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      100,    0,                              1,      OUT_P888},
28         { {     "3840x2160p@50Hz",      50,     3840,   2160,   594000000,      296,    1056,   72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      96,     HDMI_3840X2160P_50HZ_4_3,       1,      OUT_P888},
29         { {     "3840x2160p@60Hz",      60,     3840,   2160,   594000000,      296,    176,    72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      97,     HDMI_3840X2160P_60HZ_4_3,       1,      OUT_P888},
30         { {     "4096x2160p@50Hz",      50,     4096,   2160,   594000000,      128,    968,    72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      101,    0,                              1,      OUT_P888},
31         { {     "4096x2160p@60Hz",      60,     4096,   2160,   594000000,      128,    88,     72,     8,      88,     10,     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      102,    0,                              1,      OUT_P888},
32         { {     "800x600p@60Hz",        60,     800,    600,    40000000,       88,     40,     23,     1,      128,    4,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      1 | HDMI_VIDEO_DMT,     0,              1,      OUT_P888},
33         { {     "1024x768p@60Hz",       60,     1024,   768,    65000000,       160,    24,     29,     3,      136,    6,                      0,                              0,      0       },      2 | HDMI_VIDEO_DMT,     0,              1,      OUT_P888},
34         { {     "1280x960p@60Hz",       60,     1280,   960,    108000000,      312,    96,     36,     1,      112,    3,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      3 | HDMI_VIDEO_DMT,     0,              1,      OUT_P888},
35         { {     "1280x1024p@60Hz",      60,     1280,   1024,   108000000,      248,    48,     38,     1,      112,    3,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      4 | HDMI_VIDEO_DMT,     0,              1,      OUT_P888},
36         { {     "1360x768p@60Hz",       60,     1360,   768,    85500000,       256,    64,     18,     3,      112,    6,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      5 | HDMI_VIDEO_DMT,     0,              1,      OUT_P888},
37         { {     "1366x768p@60Hz",       60,     1366,   768,    85500000,       213,    70,     24,     3,      143,    3,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      6 | HDMI_VIDEO_DMT,     0,              1,      OUT_P888},
38         { {     "1440x900p@60Hz",       60,     1440,   900,    106500000,      232,    80,     25,     3,      152,    6,              FB_SYNC_VERT_HIGH_ACT,                  0,      0       },      7 | HDMI_VIDEO_DMT,     0,              1,      OUT_P888},
39         { {     "1600x900p@60Hz",       60,     1600,   900,    108000000,      96,     24,     96,     1,      80,     3,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   0,      0       },      8 | HDMI_VIDEO_DMT,     0,              1,      OUT_P888},
40         { {     "1680x1050@60Hz",       60,     1680,   1050,   146250000,      280,    104,    30,     3,      176,    6,              FB_SYNC_VERT_HIGH_ACT,                  0,      0       },      9 | HDMI_VIDEO_DMT,     0,              1,      OUT_P888},
41 };
42
43 static int hdmi_set_info(struct rk_screen *screen, struct hdmi *hdmi)
44 {
45         int i, vic;
46         struct fb_videomode *mode;
47
48         if (screen == NULL || hdmi == NULL)
49                 return HDMI_ERROR_FALSE;
50
51         if (hdmi->vic == 0)
52                 hdmi->vic = hdmi->property->defaultmode;
53
54         if (hdmi->vic & HDMI_VIDEO_DMT)
55                 vic = hdmi->vic;
56         else
57                 vic = hdmi->vic & HDMI_VIC_MASK;
58         for (i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
59                 if (hdmi_mode[i].vic == vic ||
60                     hdmi_mode[i].vic_2nd == vic)
61                         break;
62         }
63         if (i == ARRAY_SIZE(hdmi_mode))
64                 return HDMI_ERROR_FALSE;
65
66         memset(screen, 0, sizeof(struct rk_screen));
67
68         /* screen type & face */
69         screen->type = SCREEN_HDMI;
70         if (hdmi->video.color_input == HDMI_COLOR_RGB_0_255)
71                 screen->color_mode = COLOR_RGB;
72         else
73                 screen->color_mode = COLOR_YCBCR;
74         if (hdmi->vic & HDMI_VIDEO_YUV420) {
75                 if (hdmi->video.color_output_depth == 10)
76                         screen->face = OUT_YUV_420_10BIT;
77                 else
78                         screen->face = OUT_YUV_420;
79         } else {
80                 if (hdmi->video.color_output_depth == 10)
81                         screen->face = OUT_P101010;
82                 else
83                         screen->face = hdmi_mode[i].interface;
84         }
85         screen->pixelrepeat = hdmi_mode[i].pixelrepeat - 1;
86         mode = (struct fb_videomode *)&(hdmi_mode[i].mode);
87
88         screen->mode = *mode;
89         if (hdmi->video.format_3d == HDMI_3D_FRAME_PACKING) {
90                 screen->mode.pixclock = 2 * mode->pixclock;
91                 if (mode->vmode == 0) {
92                         screen->mode.yres = 2 * mode->yres +
93                                         mode->upper_margin +
94                                         mode->lower_margin +
95                                         mode->vsync_len;
96                 } else {
97                         screen->mode.yres = 2 * mode->yres +
98                                             3 * (mode->upper_margin +
99                                                  mode->lower_margin +
100                                                  mode->vsync_len) + 2;
101                         screen->mode.vmode = 0;
102                 }
103         }
104         /* Pin polarity */
105         if (FB_SYNC_HOR_HIGH_ACT & mode->sync)
106                 screen->pin_hsync = 1;
107         else
108                 screen->pin_hsync = 0;
109         if (FB_SYNC_VERT_HIGH_ACT & mode->sync)
110                 screen->pin_vsync = 1;
111         else
112                 screen->pin_vsync = 0;
113
114         screen->pin_den = 0;
115         screen->pin_dclk = 1;
116
117         /* Swap rule */
118         if (hdmi->soctype > HDMI_SOC_RK3288 &&
119             screen->color_mode > COLOR_RGB &&
120             (screen->face == OUT_P888 ||
121              screen->face == OUT_P101010))
122                 screen->swap_rb = 1;
123         else
124                 screen->swap_rb = 0;
125         screen->swap_rg = 0;
126         screen->swap_gb = 0;
127         screen->swap_delta = 0;
128         screen->swap_dumy = 0;
129
130         /* Operation function*/
131         screen->init = NULL;
132         screen->standby = NULL;
133
134         screen->overscan.left = hdmi->xscale;
135         screen->overscan.top = hdmi->yscale;
136         screen->overscan.right = hdmi->xscale;
137         screen->overscan.bottom = hdmi->yscale;
138         return 0;
139 }
140
141 /**
142  * hdmi_find_best_mode: find the video mode nearest to input vic
143  * @hdmi:
144  * @vic: input vic
145  *
146  * NOTES:
147  * If vic is zero, return the high resolution video mode vic.
148  */
149 int hdmi_find_best_mode(struct hdmi *hdmi, int vic)
150 {
151         struct list_head *pos, *head = &hdmi->edid.modelist;
152         struct display_modelist *modelist;
153         int found = 0;
154 /*      pr_info("%s vic %d\n", __FUNCTION__, vic); */
155         if (vic) {
156                 list_for_each(pos, head) {
157                         modelist =
158                                 list_entry(pos,
159                                            struct display_modelist, list);
160                         if (modelist->vic == vic) {
161                                 found = 1;
162                                 break;
163                         }
164                 }
165         }
166         if ((vic == 0 || found == 0) && head->next != head) {
167                 /* If parse edid error, we select default mode; */
168                 if (hdmi->edid.specs == NULL ||
169                     hdmi->edid.specs->modedb_len == 0)
170                         return hdmi->property->defaultmode;
171                         /*modelist = list_entry(head->prev,
172                                         struct display_modelist, list);*/
173                 else
174                         modelist = list_entry(head->next,
175                                               struct display_modelist, list);
176         }
177
178         if (modelist != NULL)
179                 return modelist->vic;
180         else
181                 return 0;
182 }
183 /**
184  * hdmi_set_lcdc: switch lcdc mode to required video mode
185  * @hdmi:
186  *
187  * NOTES:
188  *
189  */
190 int hdmi_set_lcdc(struct hdmi *hdmi)
191 {
192         int rc = 0;
193         struct rk_screen screen;
194
195         rc = hdmi_set_info(&screen, hdmi);
196
197         if (rc == 0) {
198                 rk_fb_switch_screen(&screen, 1, hdmi->lcdc->id);
199 /*              if (rk_fb_get_display_policy() != DISPLAY_POLICY_BOX)
200                         rk_fb_disp_scale(hdmi->xscale,
201                                          hdmi->yscale,
202                                          hdmi->lcdc->id);
203 */      }
204         return rc;
205 }
206
207 /**
208  * hdmi_videomode_compare - compare 2 videomodes
209  * @mode1: first videomode
210  * @mode2: second videomode
211  *
212  * RETURNS:
213  * 1 if mode1 > mode2, 0 if mode1 = mode2, -1 mode1 < mode2
214  */
215 static int hdmi_videomode_compare(const struct fb_videomode *mode1,
216                                   const struct fb_videomode *mode2)
217 {
218         if (mode1->xres > mode2->xres)
219                 return 1;
220
221         if (mode1->xres == mode2->xres) {
222                 if (mode1->yres > mode2->yres)
223                         return 1;
224                 if (mode1->yres == mode2->yres) {
225                         if (mode1->vmode < mode2->vmode)
226                                 return 1;
227                         if (mode1->pixclock > mode2->pixclock)
228                                 return 1;
229                         if (mode1->pixclock == mode2->pixclock) {
230                                 if (mode1->refresh > mode2->refresh)
231                                         return 1;
232                                 if (mode1->refresh == mode2->refresh) {
233                                         if (mode2->flag > mode1->flag)
234                                                 return 1;
235                                         if (mode2->flag < mode1->flag)
236                                                 return -1;
237                                         if (mode2->vmode > mode1->vmode)
238                                                 return 1;
239                                         if (mode2->vmode == mode1->vmode)
240                                                 return 0;
241                                 }
242                         }
243                 }
244         }
245         return -1;
246 }
247
248 /**
249  * hdmi_add_vic - add entry to modelist according vic
250  * @vic: vic to be added
251  * @head: struct list_head of modelist
252  *
253  * NOTES:
254  * Will only add unmatched mode entries
255  */
256 int hdmi_add_vic(int vic, struct list_head *head)
257 {
258         struct list_head *pos;
259         struct display_modelist *modelist;
260         int found = 0, v;
261
262         /*pr_info("%s vic %d\n", __FUNCTION__, vic);*/
263         if (vic == 0)
264                 return -1;
265
266         list_for_each(pos, head) {
267                 modelist = list_entry(pos, struct display_modelist, list);
268                 v = modelist->vic;
269                 if (v == vic) {
270                         found = 1;
271                         break;
272                 }
273         }
274         if (!found) {
275                 modelist = kmalloc(sizeof(*modelist),
276                                    GFP_KERNEL);
277
278                 if (!modelist)
279                         return -ENOMEM;
280                 memset(modelist, 0, sizeof(struct display_modelist));
281                 modelist->vic = vic;
282                 list_add_tail(&modelist->list, head);
283         }
284         return 0;
285 }
286
287 /**
288  * hdmi_add_videomode: adds videomode entry to modelist
289  * @mode: videomode to be added
290  * @head: struct list_head of modelist
291  *
292  * NOTES:
293  * Will only add unmatched mode entries
294  */
295 static int hdmi_add_videomode(const struct fb_videomode *mode,
296                               struct list_head *head)
297 {
298         struct list_head *pos;
299         struct display_modelist *modelist, *modelist_new;
300         struct fb_videomode *m;
301         int i, found = 0;
302
303         for (i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
304                 m = (struct fb_videomode *)&(hdmi_mode[i].mode);
305                 if (fb_mode_is_equal(m, mode)) {
306                         found = 1;
307                         break;
308                 }
309         }
310
311         if (found) {
312                 list_for_each(pos, head) {
313                         modelist = list_entry(pos,
314                                               struct display_modelist, list);
315                         m = &modelist->mode;
316                         if (fb_mode_is_equal(m, mode))
317                                 return 0;
318                         else if (hdmi_videomode_compare(m, mode) == -1)
319                                 break;
320                 }
321
322                 modelist_new = kmalloc(sizeof(*modelist_new), GFP_KERNEL);
323                 if (!modelist_new)
324                         return -ENOMEM;
325                 memset(modelist_new, 0, sizeof(struct display_modelist));
326                 modelist_new->mode = hdmi_mode[i].mode;
327                 modelist_new->vic = hdmi_mode[i].vic;
328                 list_add_tail(&modelist_new->list, pos);
329         }
330
331         return 0;
332 }
333
334 /**
335  * hdmi_sort_modelist: sort modelist of edid
336  * @edid: edid to be sort
337  */
338 static void hdmi_sort_modelist(struct hdmi_edid *edid, int feature)
339 {
340         struct list_head *pos, *pos_new;
341         struct list_head head_new, *head = &edid->modelist;
342         struct display_modelist *modelist, *modelist_new, *modelist_n;
343         struct fb_videomode *m, *m_new;
344         int i, compare, vic;
345
346         INIT_LIST_HEAD(&head_new);
347         list_for_each(pos, head) {
348                 modelist = list_entry(pos, struct display_modelist, list);
349                 /*pr_info("%s vic %d\n", __function__, modelist->vic);*/
350                 for (i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
351                         if (modelist->vic & HDMI_VIDEO_DMT) {
352                                 if (feature & SUPPORT_VESA_DMT)
353                                         vic = modelist->vic;
354                                 else
355                                         continue;
356                         } else {
357                                 vic = modelist->vic & HDMI_VIC_MASK;
358                         }
359                         if (vic == hdmi_mode[i].vic ||
360                             vic == hdmi_mode[i].vic_2nd) {
361                                 if ((feature & SUPPORT_4K) == 0 &&
362                                     hdmi_mode[i].mode.xres >= 3840)
363                                         continue;
364                                 if ((feature & SUPPORT_4K_4096) == 0 &&
365                                     hdmi_mode[i].mode.xres == 4096)
366                                         continue;
367                                 if ((feature & SUPPORT_TMDS_600M) == 0 &&
368                                     !(modelist->vic & HDMI_VIDEO_YUV420) &&
369                                     hdmi_mode[i].mode.pixclock > 340000000)
370                                         continue;
371                                 if ((modelist->vic & HDMI_VIDEO_YUV420) &&
372                                     (feature & SUPPORT_YUV420) == 0)
373                                         continue;
374                                 if ((feature & SUPPORT_1080I) == 0 &&
375                                     hdmi_mode[i].mode.xres == 1920 &&
376                                     (hdmi_mode[i].mode.vmode &
377                                      FB_VMODE_INTERLACED))
378                                         continue;
379                                 if ((feature & SUPPORT_480I_576I) == 0 &&
380                                     hdmi_mode[i].mode.xres == 720 &&
381                                     hdmi_mode[i].mode.vmode &
382                                      FB_VMODE_INTERLACED)
383                                         continue;
384                                 vic = modelist->vic;
385                                 modelist->vic = hdmi_mode[i].vic;
386                                 modelist->mode = hdmi_mode[i].mode;
387                                 if (vic & HDMI_VIDEO_YUV420) {
388                                         modelist->vic |= HDMI_VIDEO_YUV420;
389                                         modelist->mode.flag = 1;
390                                 }
391                                 compare = 1;
392                                 m = (struct fb_videomode *)&(modelist->mode);
393                                 list_for_each(pos_new, &head_new) {
394                                         modelist_new =
395                                         list_entry(pos_new,
396                                                    struct display_modelist,
397                                                    list);
398                                         m_new = &modelist_new->mode;
399                                         compare =
400                                         hdmi_videomode_compare(m, m_new);
401                                         if (compare != -1)
402                                                 break;
403                                 }
404                                 if (compare != 0) {
405                                         modelist_n =
406                                                 kmalloc(sizeof(*modelist_n),
407                                                         GFP_KERNEL);
408                                         if (!modelist_n)
409                                                 return;
410                                         *modelist_n = *modelist;
411                                         list_add_tail(&modelist_n->list,
412                                                       pos_new);
413                                 }
414                                 break;
415                         }
416                 }
417         }
418         fb_destroy_modelist(head);
419         if (head_new.next == &head_new) {
420                 pr_info("There is no available video mode in EDID.\n");
421                 INIT_LIST_HEAD(&edid->modelist);
422         } else {
423                 edid->modelist = head_new;
424                 edid->modelist.prev->next = &edid->modelist;
425                 edid->modelist.next->prev = &edid->modelist;
426         }
427 }
428
429 /**
430  * hdmi_ouputmode_select - select hdmi transmitter output mode: hdmi or dvi?
431  * @hdmi: handle of hdmi
432  * @edid_ok: get EDID data success or not, HDMI_ERROR_SUCESS means success.
433  */
434 int hdmi_ouputmode_select(struct hdmi *hdmi, int edid_ok)
435 {
436         struct list_head *head = &hdmi->edid.modelist;
437         struct fb_monspecs *specs = hdmi->edid.specs;
438         struct fb_videomode *modedb = NULL, *mode = NULL;
439         int i, pixclock, feature = hdmi->property->feature;
440
441         if (edid_ok != HDMI_ERROR_SUCESS) {
442                 dev_err(hdmi->dev, "warning: EDID error, assume sink as HDMI !!!!");
443                 hdmi->edid.status = -1;
444                 hdmi->edid.sink_hdmi = 1;
445                 hdmi->edid.baseaudio_support = 1;
446                 hdmi->edid.ycbcr444 = 0;
447                 hdmi->edid.ycbcr422 = 0;
448         }
449
450         if (head->next == head) {
451                 dev_info(hdmi->dev,
452                          "warning: no CEA video mode parsed from EDID !!!!\n");
453                 /* If EDID get error, list all system supported mode.
454                    If output mode is set to DVI and EDID is ok, check
455                    the output timing.
456                 */
457                 if (hdmi->edid.sink_hdmi == 0 && specs && specs->modedb_len) {
458                         /* Get max resolution timing */
459                         modedb = &specs->modedb[0];
460                         for (i = 0; i < specs->modedb_len; i++) {
461                                 if (specs->modedb[i].xres > modedb->xres)
462                                         modedb = &specs->modedb[i];
463                                 else if (specs->modedb[i].xres ==
464                                          modedb->xres &&
465                                          specs->modedb[i].yres > modedb->yres)
466                                         modedb = &specs->modedb[i];
467                         }
468                         /* For some monitor, the max pixclock read from EDID
469                            is smaller than the clock of max resolution mode
470                            supported. We fix it. */
471                         pixclock = PICOS2KHZ(modedb->pixclock);
472                         pixclock /= 250;
473                         pixclock *= 250;
474                         pixclock *= 1000;
475                         if (pixclock == 148250000)
476                                 pixclock = 148500000;
477                         if (pixclock > specs->dclkmax)
478                                 specs->dclkmax = pixclock;
479                 }
480
481                 for (i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
482                         mode = (struct fb_videomode *)&(hdmi_mode[i].mode);
483                         if (modedb) {
484                                 if ((mode->pixclock < specs->dclkmin) ||
485                                     (mode->pixclock > specs->dclkmax) ||
486                                     (mode->refresh < specs->vfmin) ||
487                                     (mode->refresh > specs->vfmax) ||
488                                     (mode->xres > modedb->xres) ||
489                                     (mode->yres > modedb->yres))
490                                         continue;
491                         } else {
492                                 /* If there is no valid information in EDID,
493                                    just list common hdmi foramt. */
494                                 if (mode->xres > 3840 ||
495                                     mode->refresh < 50 ||
496                                     (mode->vmode & FB_VMODE_INTERLACED) ||
497                                     hdmi_mode[i].vic & HDMI_VIDEO_DMT)
498                                         continue;
499                         }
500                         if ((feature & SUPPORT_TMDS_600M) == 0 &&
501                             mode->pixclock > 340000000)
502                                 continue;
503                         if ((feature & SUPPORT_4K) == 0 &&
504                             mode->xres >= 3840)
505                                 continue;
506                         if ((feature & SUPPORT_4K_4096) == 0 &&
507                             mode->xres == 4096)
508                                 continue;
509                         if ((feature & SUPPORT_1080I) == 0 &&
510                             mode->xres == 1920 &&
511                             (mode->vmode & FB_VMODE_INTERLACED))
512                                 continue;
513                         if ((feature & SUPPORT_480I_576I) == 0 &&
514                             mode->xres == 720 &&
515                             (mode->vmode & FB_VMODE_INTERLACED))
516                                 continue;
517                         hdmi_add_videomode(mode, head);
518                 }
519         } else {
520                 /* There are some video mode is not defined in EDID extend
521                    block, so we need to check first block data.*/
522                 if (specs && specs->modedb_len) {
523                         for (i = 0; i < specs->modedb_len; i++) {
524                                 modedb = &specs->modedb[i];
525                                 pixclock = hdmi_videomode_to_vic(modedb);
526                                 if (pixclock)
527                                         hdmi_add_vic(pixclock, head);
528                         }
529                 }
530                 hdmi_sort_modelist(&hdmi->edid, hdmi->property->feature);
531         }
532
533         return HDMI_ERROR_SUCESS;
534 }
535
536 /**
537  * hdmi_videomode_to_vic: transverse video mode to vic
538  * @vmode: videomode to transverse
539  *
540  */
541 int hdmi_videomode_to_vic(struct fb_videomode *vmode)
542 {
543         struct fb_videomode *mode;
544         unsigned int vic = 0;
545         int i = 0;
546
547         for (i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
548                 mode = (struct fb_videomode *)&(hdmi_mode[i].mode);
549                 if (vmode->vmode == mode->vmode &&
550                     vmode->refresh == mode->refresh &&
551                     vmode->xres == mode->xres &&
552                     vmode->yres == mode->yres &&
553                     vmode->left_margin == mode->left_margin &&
554                     vmode->right_margin == mode->right_margin &&
555                     vmode->upper_margin == mode->upper_margin &&
556                     vmode->lower_margin == mode->lower_margin &&
557                     vmode->hsync_len == mode->hsync_len &&
558                     vmode->vsync_len == mode->vsync_len) {
559                         vic = hdmi_mode[i].vic;
560                         break;
561                 }
562         }
563         return vic;
564 }
565
566 /**
567  * hdmi_vic2timing: transverse vic mode to video timing
568  * @vmode: vic to transverse
569  *
570  */
571 const struct hdmi_video_timing *hdmi_vic2timing(int vic)
572 {
573         int i;
574
575         if (vic == 0)
576                 return NULL;
577
578         for (i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
579                 if (hdmi_mode[i].vic == vic || hdmi_mode[i].vic_2nd == vic)
580                         return &(hdmi_mode[i]);
581         }
582         return NULL;
583 }
584
585 /**
586  * hdmi_vic_to_videomode: transverse vic mode to video mode
587  * @vmode: vic to transverse
588  *
589  */
590 const struct fb_videomode *hdmi_vic_to_videomode(int vic)
591 {
592         int i, vid;
593
594         if (vic == 0)
595                 return NULL;
596         else if (vic & HDMI_VIDEO_DMT)
597                 vid = vic;
598         else
599                 vid = vic & HDMI_VIC_MASK;
600         for (i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
601                 if (hdmi_mode[i].vic == vid ||
602                     hdmi_mode[i].vic_2nd == vid)
603                         return &hdmi_mode[i].mode;
604         }
605         return NULL;
606 }
607
608 /**
609  * hdmi_init_modelist: initial hdmi mode list
610  * @hdmi:
611  *
612  * NOTES:
613  *
614  */
615 void hdmi_init_modelist(struct hdmi *hdmi)
616 {
617         int i, feature;
618         struct list_head *head = &hdmi->edid.modelist;
619
620         feature = hdmi->property->feature;
621         INIT_LIST_HEAD(&hdmi->edid.modelist);
622         for (i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
623                 if (hdmi_mode[i].vic & HDMI_VIDEO_DMT)
624                         continue;
625                 if ((feature & SUPPORT_TMDS_600M) == 0 &&
626                     hdmi_mode[i].mode.pixclock > 340000000)
627                         continue;
628                 if ((feature & SUPPORT_4K) == 0 &&
629                     hdmi_mode[i].mode.xres >= 3840)
630                         continue;
631                 if ((feature & SUPPORT_4K_4096) == 0 &&
632                     hdmi_mode[i].mode.xres == 4096)
633                         continue;
634                 if ((feature & SUPPORT_1080I) == 0 &&
635                     hdmi_mode[i].mode.xres == 1920 &&
636                     (hdmi_mode[i].mode.vmode & FB_VMODE_INTERLACED))
637                         continue;
638                 if ((feature & SUPPORT_480I_576I) == 0 &&
639                     hdmi_mode[i].mode.xres == 720 &&
640                     (hdmi_mode[i].mode.vmode & FB_VMODE_INTERLACED))
641                         continue;
642                 hdmi_add_videomode(&(hdmi_mode[i].mode), head);
643         }
644 }