hdmi:edid: improve edid check redundancy.
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / hdmi / rockchip-hdmi-edid.c
1 #include "rockchip-hdmi.h"
2 #include "../../edid.h"
3
4 #ifdef EDIDDEBUG
5 #define EDBG    DBG
6 #else
7 #define EDBG(format, ...)
8 #endif
9
10 enum {
11         E_HDMI_EDID_SUCCESS = 0,
12         E_HDMI_EDID_PARAM,
13         E_HDMI_EDID_HEAD,
14         E_HDMI_EDID_CHECKSUM,
15         E_HDMI_EDID_VERSION,
16         E_HDMI_EDID_UNKOWNDATA,
17         E_HDMI_EDID_NOMEMORY
18 };
19
20 static int hdmi_edid_checksum(unsigned char *buf)
21 {
22         int i;
23         int checksum = 0;
24
25         for (i = 0; i < HDMI_EDID_BLOCK_SIZE; i++)
26                 checksum += buf[i];
27
28         checksum &= 0xff;
29
30         if (checksum == 0)
31                 return E_HDMI_EDID_SUCCESS;
32         else
33                 return E_HDMI_EDID_CHECKSUM;
34 }
35
36 /*
37         @Des    Parse Detail Timing Descriptor.
38         @Param  buf     :       pointer to DTD data.
39         @Param  pvic:   VIC of DTD descripted.
40  */
41 static int hdmi_edid_parse_dtd(unsigned char *block, struct fb_videomode *mode)
42 {
43         mode->xres = H_ACTIVE;
44         mode->yres = V_ACTIVE;
45         mode->pixclock = PIXEL_CLOCK;
46 /*      mode->pixclock /= 1000;
47         mode->pixclock = KHZ2PICOS(mode->pixclock);
48 */      mode->right_margin = H_SYNC_OFFSET;
49         mode->left_margin = (H_ACTIVE + H_BLANKING) -
50                 (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
51         mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
52                 V_SYNC_WIDTH;
53         mode->lower_margin = V_SYNC_OFFSET;
54         mode->hsync_len = H_SYNC_WIDTH;
55         mode->vsync_len = V_SYNC_WIDTH;
56         if (HSYNC_POSITIVE)
57                 mode->sync |= FB_SYNC_HOR_HIGH_ACT;
58         if (VSYNC_POSITIVE)
59                 mode->sync |= FB_SYNC_VERT_HIGH_ACT;
60         mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
61                                      (V_ACTIVE + V_BLANKING));
62         if (INTERLACED) {
63                 mode->yres *= 2;
64                 mode->upper_margin *= 2;
65                 mode->lower_margin *= 2;
66                 mode->vsync_len *= 2;
67                 mode->vmode |= FB_VMODE_INTERLACED;
68         }
69         mode->flag = FB_MODE_IS_DETAILED;
70
71         EDBG("<<<<<<<<Detailed Time>>>>>>>>>\n");
72         EDBG("%d KHz Refresh %d Hz",
73              PIXEL_CLOCK/1000, mode->refresh);
74         EDBG("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,
75              H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
76         EDBG("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,
77              V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
78         EDBG("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",
79              (VSYNC_POSITIVE) ? "+" : "-");
80         return E_HDMI_EDID_SUCCESS;
81 }
82
83 int hdmi_edid_parse_base(unsigned char *buf,
84                          int *extend_num, struct hdmi_edid *pedid)
85 {
86         int rc = E_HDMI_EDID_SUCCESS;
87
88         if (buf == NULL || extend_num == NULL)
89                 return E_HDMI_EDID_PARAM;
90
91         *extend_num = buf[0x7e];
92         #ifdef DEBUG
93         EDBG("[EDID] extend block num is %d\n", buf[0x7e]);
94         #endif
95
96         /* Check first 8 byte to ensure it is an edid base block. */
97         if (buf[0] != 0x00 ||
98             buf[1] != 0xFF ||
99             buf[2] != 0xFF ||
100             buf[3] != 0xFF ||
101             buf[4] != 0xFF ||
102             buf[5] != 0xFF ||
103             buf[6] != 0xFF ||
104             buf[7] != 0x00) {
105                 pr_err("[EDID] check header error\n");
106                 rc = E_HDMI_EDID_HEAD;
107                 goto out;
108         }
109
110         /* Checksum */
111         rc = hdmi_edid_checksum(buf);
112         if (rc != E_HDMI_EDID_SUCCESS) {
113                 pr_err("[EDID] base block checksum error\n");
114                 rc = E_HDMI_EDID_CHECKSUM;
115                 goto out;
116         }
117
118         pedid->specs = kzalloc(sizeof(*pedid->specs), GFP_KERNEL);
119         if (pedid->specs == NULL)
120                 return E_HDMI_EDID_NOMEMORY;
121
122         fb_edid_to_monspecs(buf, pedid->specs);
123
124 out:
125         if (rc != E_HDMI_EDID_SUCCESS && *extend_num > 4)
126                 return rc;
127         else
128                 return E_HDMI_EDID_SUCCESS;
129 }
130
131 /* Parse CEA Short Video Descriptor */
132 static int hdmi_edid_get_cea_svd(unsigned char *buf, struct hdmi_edid *pedid)
133 {
134         int count, i, vic;
135
136         count = buf[0] & 0x1F;
137         for (i = 0; i < count; i++) {
138                 EDBG("[CEA] %02x VID %d native %d\n",
139                      buf[1 + i], buf[1 + i] & 0x7f, buf[1 + i] >> 7);
140                 vic = buf[1 + i] & 0x7f;
141                 hdmi_add_vic(vic, &pedid->modelist);
142         }
143 /*
144         struct list_head *pos;
145         struct display_modelist *modelist;
146
147         list_for_each(pos, &pedid->modelist) {
148                 modelist = list_entry(pos, struct display_modelist, list);
149                 pr_info("%s vic %d\n", __FUNCTION__, modelist->vic);
150         }
151 */      return 0;
152 }
153
154 /* Parse CEA Short Audio Descriptor */
155 static int hdmi_edid_parse_cea_sad(unsigned char *buf, struct hdmi_edid *pedid)
156 {
157         int i, count;
158
159         count = buf[0] & 0x1F;
160         pedid->audio = kmalloc((count/3)*sizeof(struct hdmi_audio), GFP_KERNEL);
161         if (pedid->audio == NULL)
162                 return E_HDMI_EDID_NOMEMORY;
163
164         pedid->audio_num = count/3;
165         for (i = 0; i < pedid->audio_num; i++) {
166                 pedid->audio[i].type = (buf[1 + i*3] >> 3) & 0x0F;
167                 pedid->audio[i].channel = (buf[1 + i*3] & 0x07) + 1;
168                 pedid->audio[i].rate = buf[1 + i*3 + 1];
169                 if (pedid->audio[i].type == HDMI_AUDIO_LPCM)
170                         pedid->audio[i].word_length = buf[1 + i*3 + 2];
171
172 /*              pr_info("type %d channel %d rate %d word length %d\n",
173                         pedid->audio[i].type, pedid->audio[i].channel,
174                         pedid->audio[i].rate, pedid->audio[i].word_length);
175 */      }
176         return E_HDMI_EDID_SUCCESS;
177 }
178
179 static int hdmi_edid_parse_3dinfo(unsigned char *buf, struct list_head *head)
180 {
181         int i, j, len = 0, format_3d, vic_mask;
182         unsigned char offset = 2, vic_2d, structure_3d;
183         struct list_head *pos;
184         struct display_modelist *modelist;
185
186         if (buf[1] & 0xe0) {
187                 len = (buf[1] & 0xe0) >> 5;
188                 for (i = 0; i < len; i++) {
189                         if (buf[offset])
190                                 hdmi_add_vic((96 - buf[offset]), head);
191                         offset++;
192                 }
193         }
194
195         if (buf[0] & 0x80) {
196                 /* 3d supported */
197                 len += (buf[1] & 0x1F) + 2;
198                 if (((buf[0] & 0x60) == 0x40) || ((buf[0] & 0x60) == 0x20)) {
199                         format_3d = buf[offset++] << 8;
200                         format_3d |= buf[offset++];
201                         if ((buf[0] & 0x60) == 0x20) {
202                                 vic_mask = 0xFFFF;
203                         } else {
204                                 vic_mask  = buf[offset++] << 8;
205                                 vic_mask |= buf[offset++];
206                         }
207                 } else {
208                         format_3d = 0;
209                         vic_mask = 0;
210                 }
211
212                 for (i = 0; i < 16; i++) {
213                         if (vic_mask & (1 << i)) {
214                                 j = 0;
215                                 for (pos = (head)->next; pos != (head);
216                                         pos = pos->next) {
217                                         if (j++ == i) {
218                                                 modelist =
219                         list_entry(pos, struct display_modelist, list);
220                                                 modelist->format_3d = format_3d;
221                                                 break;
222                                         }
223                                 }
224                         }
225                 }
226                 while (offset < len) {
227                         vic_2d = (buf[offset] & 0xF0) >> 4;
228                         structure_3d = (buf[offset++] & 0x0F);
229                         j = 0;
230                         for (pos = (head)->next; pos != (head);
231                                 pos = pos->next) {
232                                 j++;
233                                 if (j == vic_2d) {
234                                         modelist =
235                                 list_entry(pos, struct display_modelist, list);
236                                         modelist->format_3d |=
237                                                 (1 << structure_3d);
238                                         if (structure_3d & 0x08)
239                                                 modelist->detail_3d =
240                                                 (buf[offset++] & 0xF0) >> 4;
241                                         break;
242                                 }
243                         }
244                 }
245                 /* mandatory formats */
246                 for (pos = (head)->next; pos != (head); pos = pos->next) {
247                         modelist = list_entry(pos,
248                                               struct display_modelist,
249                                               list);
250                         if (modelist->vic == HDMI_1920X1080P_24HZ ||
251                             modelist->vic == HDMI_1280X720P_60HZ ||
252                             modelist->vic == HDMI_1280X720P_50HZ) {
253                                 modelist->format_3d |=
254                                         (1 << HDMI_3D_FRAME_PACKING) |
255                                         (1 << HDMI_3D_TOP_BOOTOM);
256                         } else if (modelist->vic == HDMI_1920X1080I_60HZ ||
257                                    modelist->vic == HDMI_1920X1080I_50HZ) {
258                                 modelist->format_3d |=
259                                         (1 << HDMI_3D_SIDE_BY_SIDE_HALF);
260                         }
261                 }
262         }
263
264         return 0;
265 }
266 static int hdmi_edmi_parse_vsdb(unsigned char *buf, struct hdmi_edid *pedid,
267                                 int cur_offset, int IEEEOUI)
268 {
269         int count, buf_offset;
270
271         count = buf[cur_offset] & 0x1F;
272         switch (IEEEOUI) {
273         case 0x0c03:
274                 pedid->sink_hdmi = 1;
275                 pedid->cecaddress = buf[cur_offset + 5];
276                 pedid->cecaddress |= buf[cur_offset + 4] << 8;
277                 EDBG("[CEA] CEC Physical addres is 0x%08x.\n",
278                      pedid->cecaddress);
279                 if (count > 6)
280                         pedid->deepcolor = (buf[cur_offset + 6] >> 3) & 0x0F;
281                 if (count > 7) {
282                         pedid->maxtmdsclock = buf[cur_offset + 7] * 5000000;
283                         EDBG("[CEA] maxtmdsclock is %d.\n",
284                              pedid->maxtmdsclock);
285                 }
286                 if (count > 8) {
287                         pedid->fields_present = buf[cur_offset + 8];
288                         EDBG("[CEA] fields_present is 0x%02x.\n",
289                              pedid->fields_present);
290                 }
291                 buf_offset = cur_offset + 9;
292                 if (pedid->fields_present & 0x80) {
293                         pedid->video_latency = buf[buf_offset++];
294                         pedid->audio_latency = buf[buf_offset++];
295                 }
296                 if (pedid->fields_present & 0x40) {
297                         pedid->interlaced_video_latency = buf[buf_offset++];
298                         pedid->interlaced_audio_latency = buf[buf_offset++];
299                 }
300                 if (pedid->fields_present & 0x20) {
301                         hdmi_edid_parse_3dinfo(buf + buf_offset,
302                                                &pedid->modelist);
303                 }
304                 break;
305         case 0xc45dd8:
306                 pedid->sink_hdmi = 1;
307                 if (count > 4)
308                         pedid->hf_vsdb_version = buf[cur_offset + 4];
309                 switch (pedid->hf_vsdb_version) {
310                 case 1:/*compliant with HDMI Specification 2.0*/
311                         if (count > 5) {
312                                 pedid->maxtmdsclock =
313                                         buf[cur_offset + 5] * 5000000;
314                                 EDBG("[CEA] maxtmdsclock is %d.\n",
315                                      pedid->maxtmdsclock);
316                         }
317                         if (count > 6) {
318                                 pedid->scdc_present = buf[cur_offset+6] >> 7;
319                                 pedid->rr_capable =
320                                         (buf[cur_offset+6]&0x40) >> 6;
321                                 pedid->lte_340mcsc_scramble =
322                                         (buf[cur_offset+6]&0x08) >> 3;
323                                 pedid->independent_view =
324                                         (buf[cur_offset+6]&0x04) >> 2;
325                                 pedid->dual_view =
326                                         (buf[cur_offset+6]&0x02) >> 1;
327                                 pedid->osd_disparity_3d =
328                                         buf[cur_offset+6] & 0x01;
329                         }
330                         if (count > 7) {
331                                 pedid->deepcolor = buf[cur_offset+7]&0x7;
332                                 EDBG("[CEA] deepcolor is %d.\n",
333                                      pedid->deepcolor);
334                         }
335                         break;
336                 default:
337                         pr_info("hf_vsdb_version = %d\n",
338                                 pedid->hf_vsdb_version);
339                         break;
340                 }
341                 break;
342         default:
343                 pr_info("IEEOUT = 0x%x\n", IEEEOUI);
344                 break;
345         }
346         return 0;
347 }
348
349 static void hdmi_edid_parse_yuv420cmdb(unsigned char *buf, int count,
350                                        struct list_head *head)
351 {
352         struct list_head *pos;
353         struct display_modelist *modelist;
354         int i, j, yuv420_mask, vic;
355
356         for (i = 0; i < count - 1; i++) {
357                 EDBG("vic which support yuv420 mode is %x\n", buf[i]);
358                 yuv420_mask |= buf[i] << (8 * i);
359         }
360         for (i = 0; i < 32; i++) {
361                 if (yuv420_mask & (1 << i)) {
362                         j = 0;
363                         for (pos = head->next; pos != (head); pos = pos->next) {
364                                 if (j++ == i) {
365                                         modelist =
366                                 list_entry(pos, struct display_modelist, list);
367                                         vic = modelist->vic |
368                                               HDMI_VIDEO_YUV420;
369                                         hdmi_add_vic(vic, head);
370                                         break;
371                                 }
372                         }
373                 }
374         }
375 }
376
377 /* Parse CEA 861 Serial Extension. */
378 static int hdmi_edid_parse_extensions_cea(unsigned char *buf,
379                                           struct hdmi_edid *pedid)
380 {
381         unsigned int ddc_offset, native_dtd_num, cur_offset = 4;
382         unsigned int tag, IEEEOUI = 0, count, i;
383 /*      unsigned int underscan_support, baseaudio_support; */
384
385         if (buf == NULL)
386                 return E_HDMI_EDID_PARAM;
387
388         /* Check ces extension version */
389         if (buf[1] != 3) {
390                 pr_err("[CEA] error version.\n");
391                 return E_HDMI_EDID_VERSION;
392         }
393
394         ddc_offset = buf[2];
395 /*      underscan_support = (buf[3] >> 7) & 0x01;
396 */      pedid->baseaudio_support = (buf[3] >> 6) & 0x01;
397         pedid->ycbcr444 = (buf[3] >> 5) & 0x01;
398         pedid->ycbcr422 = (buf[3] >> 4) & 0x01;
399         native_dtd_num = buf[3] & 0x0F;
400 /*      EDBG("[CEA] ddc_offset %d underscan_support %d
401             baseaudio_support %d yuv_support %d
402             native_dtd_num %d\n",
403             ddc_offset, underscan_support, baseaudio_support,
404             yuv_support, native_dtd_num);
405 */      /* Parse data block */
406         while (cur_offset < ddc_offset) {
407                 tag = buf[cur_offset] >> 5;
408                 count = buf[cur_offset] & 0x1F;
409                 switch (tag) {
410                 case 0x02:      /* Video Data Block */
411                         EDBG("[CEA] Video Data Block.\n");
412                         hdmi_edid_get_cea_svd(buf + cur_offset, pedid);
413                         break;
414                 case 0x01:      /* Audio Data Block */
415                         EDBG("[CEA] Audio Data Block.\n");
416                         hdmi_edid_parse_cea_sad(buf + cur_offset, pedid);
417                         break;
418                 case 0x04:      /* Speaker Allocation Data Block */
419                         EDBG("[CEA] Speaker Allocatio Data Block.\n");
420                         break;
421                 case 0x03:      /* Vendor Specific Data Block */
422                         EDBG("[CEA] Vendor Specific Data Block.\n");
423
424                         IEEEOUI = buf[cur_offset + 3];
425                         IEEEOUI <<= 8;
426                         IEEEOUI += buf[cur_offset + 2];
427                         IEEEOUI <<= 8;
428                         IEEEOUI += buf[cur_offset + 1];
429                         EDBG("[CEA] IEEEOUI is 0x%08x.\n", IEEEOUI);
430
431                         hdmi_edmi_parse_vsdb(buf, pedid,
432                                              cur_offset, IEEEOUI);
433                         break;
434                 case 0x05:      /* VESA DTC Data Block */
435                         EDBG("[CEA] VESA DTC Data Block.\n");
436                         break;
437                 case 0x07:      /* Use Extended Tag */
438                         EDBG("[CEA] Use Extended Tag Data Block %02x.\n",
439                              buf[cur_offset + 1]);
440                         switch (buf[cur_offset + 1]) {
441                         case 0x00:
442                                 EDBG("[CEA] Video Capability Data Block\n");
443                                 EDBG("value is %02x\n", buf[cur_offset + 2]);
444                                 break;
445                         case 0x05:
446                                 EDBG("[CEA] Colorimetry Data Block\n");
447                                 EDBG("value is %02x\n", buf[cur_offset + 2]);
448                                 break;
449                         case 0x0e:
450                                 EDBG("[CEA] YCBCR 4:2:0 Video Data Block\n");
451                                 for (i = 0; i < count - 1; i++) {
452                                         EDBG("mode is %d\n",
453                                              buf[cur_offset + 2 + i]);
454                                         pedid->ycbcr420 = 1;
455                                         IEEEOUI = buf[cur_offset + 2 + i] |
456                                                   HDMI_VIDEO_YUV420;
457                                         hdmi_add_vic(IEEEOUI,
458                                                      &pedid->modelist);
459                                 }
460                                 break;
461                         case 0x0f:
462                                 EDBG("[CEA] YCBCR 4:2:0 Capability Map Data\n");
463                                 hdmi_edid_parse_yuv420cmdb(&buf[cur_offset+2],
464                                                            count,
465                                                            &pedid->modelist);
466                                 pedid->ycbcr420 = 1;
467                                 break;
468                         }
469                         break;
470                 default:
471                         pr_err("[CEA] unkowned data block tag.\n");
472                         break;
473                 }
474                 cur_offset += (buf[cur_offset] & 0x1F) + 1;
475         }
476 #if 1
477 {
478         /* Parse DTD */
479         struct fb_videomode *vmode =
480                 kmalloc(sizeof(struct fb_videomode), GFP_KERNEL);
481
482         if (vmode == NULL)
483                 return E_HDMI_EDID_SUCCESS;
484         while (ddc_offset < HDMI_EDID_BLOCK_SIZE - 2) {
485                 if (!buf[ddc_offset] && !buf[ddc_offset + 1])
486                         break;
487                 memset(vmode, 0, sizeof(struct fb_videomode));
488                 hdmi_edid_parse_dtd(buf + ddc_offset, vmode);
489                 hdmi_add_vic(hdmi_videomode_to_vic(vmode), &pedid->modelist);
490                 ddc_offset += 18;
491         }
492         kfree(vmode);
493 }
494 #endif
495         return E_HDMI_EDID_SUCCESS;
496 }
497
498 int hdmi_edid_parse_extensions(unsigned char *buf, struct hdmi_edid *pedid)
499 {
500         int rc;
501
502         if (buf == NULL || pedid == NULL)
503                 return E_HDMI_EDID_PARAM;
504
505         /* Checksum */
506         rc = hdmi_edid_checksum(buf);
507         if (rc != E_HDMI_EDID_SUCCESS) {
508                 pr_err("[EDID] extensions block checksum error\n");
509                 return E_HDMI_EDID_CHECKSUM;
510         }
511
512         switch (buf[0]) {
513         case 0xF0:
514                 EDBG("[EDID-EXTEND] Iextensions block map.\n");
515                 break;
516         case 0x02:
517                 EDBG("[EDID-EXTEND] CEA 861 Series Extension.\n");
518                 hdmi_edid_parse_extensions_cea(buf, pedid);
519                 break;
520         case 0x10:
521                 EDBG("[EDID-EXTEND] Video Timing Block Extension.\n");
522                 break;
523         case 0x40:
524                 EDBG("[EDID-EXTEND] Display Information Extension.\n");
525                 break;
526         case 0x50:
527                 EDBG("[EDID-EXTEND] Localized String Extension.\n");
528                 break;
529         case 0x60:
530                 EDBG("[EDID-EXTEND] Digital Packet Video Link Extension.\n");
531                 break;
532         default:
533                 pr_err("[EDID-EXTEND] Unkowned Extension.\n");
534                 return E_HDMI_EDID_UNKOWNDATA;
535         }
536
537         return E_HDMI_EDID_SUCCESS;
538 }