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