Merge remote-tracking branch 'origin/develop-3.10-next' into develop-3.10
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / hdmi / rk_hdmi_edid.c
1 #include "rk_hdmi.h"
2 #include "../../edid.h"
3
4 #define hdmi_edid_error(fmt, ...) \
5         printk(pr_fmt(fmt), ##__VA_ARGS__)
6
7 #if 0
8 #define hdmi_edid_debug(fmt, ...) \
9         printk(pr_fmt(fmt), ##__VA_ARGS__)
10 #else
11 #define hdmi_edid_debug(fmt, ...)
12 #endif
13
14 enum HDMI_EDID_ERRORCODE {
15         E_HDMI_EDID_SUCCESS = 0,
16         E_HDMI_EDID_PARAM,
17         E_HDMI_EDID_HEAD,
18         E_HDMI_EDID_CHECKSUM,
19         E_HDMI_EDID_VERSION,
20         E_HDMI_EDID_UNKOWNDATA,
21         E_HDMI_EDID_NOMEMORY
22 };
23
24 static const unsigned int double_aspect_vic[] = {
25         3, 7, 9, 11, 13, 15, 18, 22, 24, 26, 28, 30,
26         36, 38, 43, 45, 49, 51, 53, 55, 57, 59
27 };
28
29 static int hdmi_edid_checksum(unsigned char *buf)
30 {
31         int i;
32         int checksum = 0;
33
34         for (i = 0; i < HDMI_EDID_BLOCK_SIZE; i++)
35                 checksum += buf[i];
36
37         checksum &= 0xff;
38
39         if (checksum == 0)
40                 return E_HDMI_EDID_SUCCESS;
41         else
42                 return E_HDMI_EDID_CHECKSUM;
43 }
44
45 /*
46  * @Des Parse Detail Timing Descriptor.
47  * @Param       buf     :       pointer to DTD data.
48  * @Param       pvic:   VIC of DTD descripted.
49  */
50 static int hdmi_edid_parse_dtd(unsigned char *block, struct fb_videomode *mode)
51 {
52         mode->xres = H_ACTIVE;
53         mode->yres = V_ACTIVE;
54         mode->pixclock = PIXEL_CLOCK;
55 /*
56         mode->pixclock /= 1000;
57         mode->pixclock = KHZ2PICOS(mode->pixclock);
58 */
59         mode->right_margin = H_SYNC_OFFSET;
60         mode->left_margin = (H_ACTIVE + H_BLANKING) -
61                 (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
62         mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
63                 V_SYNC_WIDTH;
64         mode->lower_margin = V_SYNC_OFFSET;
65         mode->hsync_len = H_SYNC_WIDTH;
66         mode->vsync_len = V_SYNC_WIDTH;
67         if (HSYNC_POSITIVE)
68                 mode->sync |= FB_SYNC_HOR_HIGH_ACT;
69         if (VSYNC_POSITIVE)
70                 mode->sync |= FB_SYNC_VERT_HIGH_ACT;
71         mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
72                                      (V_ACTIVE + V_BLANKING));
73         if (INTERLACED) {
74                 mode->yres *= 2;
75                 mode->upper_margin *= 2;
76                 mode->lower_margin *= 2;
77                 mode->vsync_len *= 2;
78                 mode->vmode |= FB_VMODE_INTERLACED;
79         }
80         mode->flag = FB_MODE_IS_DETAILED;
81
82         hdmi_edid_debug("<<<<<<<<Detailed Time>>>>>>>>>\n");
83         hdmi_edid_debug("%d KHz Refresh %d Hz",  PIXEL_CLOCK/1000,
84                         mode->refresh);
85         hdmi_edid_debug("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,
86                H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
87         hdmi_edid_debug("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,
88                V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
89         hdmi_edid_debug("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",
90                (VSYNC_POSITIVE) ? "+" : "-");
91         return E_HDMI_EDID_SUCCESS;
92 }
93
94 static int hdmi_edid_parse_base(unsigned char *buf, int *extend_num,
95                                 struct hdmi_edid *pedid)
96 {
97         int rc;
98 #ifdef DEBUG
99         int i = 0;
100 #endif
101
102         if (buf == NULL || extend_num == NULL)
103                 return E_HDMI_EDID_PARAM;
104
105 #ifdef DEBUG
106         for (i = 0; i < HDMI_EDID_BLOCK_SIZE; i++) {
107                 hdmi_edid_debug("%02x ", buf[i]&0xff);
108                 if ((i+1) % 16 == 0)
109                         hdmi_edid_debug("\n");
110         }
111 #endif
112
113         /* Check first 8 byte to ensure it is an edid base block. */
114         if (buf[0] != 0x00 ||
115             buf[1] != 0xFF ||
116             buf[2] != 0xFF ||
117             buf[3] != 0xFF ||
118             buf[4] != 0xFF ||
119             buf[5] != 0xFF ||
120             buf[6] != 0xFF ||
121             buf[7] != 0x00) {
122                 hdmi_edid_error("[EDID] check header error\n");
123                 return E_HDMI_EDID_HEAD;
124         }
125
126         *extend_num = buf[0x7e];
127 #ifdef DEBUG
128         hdmi_edid_debug("[EDID] extend block num is %d\n", buf[0x7e]);
129 #endif
130
131         /* Checksum */
132         rc = hdmi_edid_checksum(buf);
133         if (rc != E_HDMI_EDID_SUCCESS) {
134                 hdmi_edid_error("[EDID] base block checksum error\n");
135                 return E_HDMI_EDID_CHECKSUM;
136         }
137
138         pedid->specs = kzalloc(sizeof(struct fb_monspecs), GFP_KERNEL);
139         if (pedid->specs == NULL)
140                 return E_HDMI_EDID_NOMEMORY;
141
142         fb_edid_to_monspecs(buf, pedid->specs);
143
144         return E_HDMI_EDID_SUCCESS;
145 }
146
147 /* Parse CEA Short Video Descriptor */
148 static int hdmi_edid_get_cea_svd(unsigned char *buf, struct hdmi_edid *pedid)
149 {
150         const struct fb_videomode *mode;
151         int count, i, j, vic;
152
153         count = buf[0] & 0x1F;
154         for (i = 0; i < count; i++) {
155                 hdmi_edid_debug("[EDID-CEA] %02x VID %d native %d\n",
156                                 buf[1 + i],
157                                 buf[1 + i] & 0x7f,
158                                 buf[1 + i] >> 7);
159         #ifndef HDMI_VERSION_2
160                 vic = buf[1 + i] & 0x7f;
161         #else
162                 vic = buf[1 + i] & 0xff;
163         #endif
164                 for (j = 0; j < ARRAY_SIZE(double_aspect_vic); j++) {
165                         if (vic == double_aspect_vic[j]) {
166                                 vic--;
167                                 break;
168                         }
169                 }
170                 if (vic) {
171                         mode = hdmi_vic_to_videomode(vic);
172                         if (mode)
173                                 hdmi_add_videomode(mode, &pedid->modelist);
174                 }
175         }
176         return 0;
177 }
178
179 /* Parse CEA Short Audio Descriptor */
180 static int hdmi_edid_parse_cea_sad(unsigned char *buf, struct hdmi_edid *pedid)
181 {
182         int i, count;
183
184         count = buf[0] & 0x1F;
185         pedid->audio = kmalloc((count / 3) * sizeof(struct hdmi_audio),
186                                 GFP_KERNEL);
187         if (pedid->audio == NULL)
188                 return E_HDMI_EDID_NOMEMORY;
189
190         pedid->audio_num = count / 3;
191         for (i = 0; i < pedid->audio_num; i++) {
192                 pedid->audio[i].type = (buf[1 + i * 3] >> 3) & 0x0F;
193                 pedid->audio[i].channel = (buf[1 + i * 3] & 0x07) + 1;
194                 pedid->audio[i].rate = buf[1 + i * 3 + 1];
195                 if (pedid->audio[i].type == HDMI_AUDIO_LPCM)    /* LPCM */
196                         pedid->audio[i].word_length = buf[1 + i * 3 + 2];
197 /*
198                 printk("[EDID-CEA] type %d channel %d rate %d word length %d\n",
199                         pedid->audio[i].type, pedid->audio[i].channel,
200                         pedid->audio[i].rate, pedid->audio[i].word_length);
201 */
202         }
203         return E_HDMI_EDID_SUCCESS;
204 }
205
206 /* Parse CEA Vendor Specific Data Block */
207 static int hdmi_edid_parse_cea_sdb(unsigned char *buf, struct hdmi_edid *pedid)
208 {
209         unsigned int count = 0, cur_offset = 0, i = 0;
210         unsigned int IEEEOUI = 0;
211         unsigned int supports_ai, dc_48bit, dc_36bit, dc_30bit, dc_y444;
212         unsigned int len_3d, len_4k;
213         unsigned char vic = 0;
214         const struct fb_videomode *mode;
215
216         count = buf[0] & 0x1F;
217         IEEEOUI = buf[3];
218         IEEEOUI <<= 8;
219         IEEEOUI += buf[2];
220         IEEEOUI <<= 8;
221         IEEEOUI += buf[1];
222         hdmi_edid_debug("[EDID-CEA] IEEEOUI is 0x%08x.\n", IEEEOUI);
223         if (IEEEOUI == 0x0c03)
224                 pedid->sink_hdmi = 1;
225
226         pedid->cecaddress = buf[cur_offset + 5];
227         pedid->cecaddress |= buf[cur_offset + 4] << 8;
228         hdmi_edid_debug("[EDID-CEA] CEC Physical addres is 0x%08x.\n", pedid->cecaddress);
229
230         if (count > 5) {
231                 pedid->deepcolor = (buf[6] >> 3) & 0x0F;
232                 supports_ai = buf[6] >> 7;
233                 dc_48bit = (buf[6] >> 6) & 0x1;
234                 dc_36bit = (buf[6] >> 5) & 0x1;
235                 dc_30bit = (buf[6] >> 4) & 0x1;
236                 dc_y444 = (buf[6] >> 3) & 0x1;
237                 hdmi_edid_debug("[EDID-CEA] supports_ai %d\n"
238                         "dc_48bit %d dc_36bit %d dc_30bit %d dc_y444 %d\n",
239                         supports_ai,
240                         dc_48bit, dc_36bit, dc_30bit, dc_y444);
241         }
242         if (count > 6)
243                 pedid->maxtmdsclock = buf[7] * 5000000;
244
245         if (count > 7) {
246                 pedid->latency_fields_present = (buf[8] & 0x80) ? 1 : 0;
247                 pedid->i_latency_fields_present = (buf[8] & 0x40) ? 1 : 0;
248                 pedid->video_present = (buf[8] & 0x20) ? 1 : 0;
249         }
250
251         cur_offset = 9;
252         if (count >= cur_offset) {
253                 if (pedid->latency_fields_present == 1) {
254                         pedid->video_latency = buf[cur_offset++];
255                         pedid->audio_latency = buf[cur_offset++];
256                 }
257                 if (count >= cur_offset && pedid->i_latency_fields_present) {
258                         pedid->interlaced_video_latency = buf[cur_offset++];
259                         pedid->interlaced_audio_latency = buf[cur_offset++];
260                 }
261         }
262
263         if (pedid->video_present == 0)
264                 return E_HDMI_EDID_SUCCESS;
265
266         if (count >= cur_offset) {
267                 pedid->support_3d = (buf[cur_offset++] & 0x80) ? 1 : 0;
268
269                 len_4k = (buf[cur_offset] >> 5) & 0x07;
270                 len_3d = buf[cur_offset] & 0x1F;
271                 cur_offset++;
272         }
273         if (count >= cur_offset && len_4k > 0) {
274                 for (i = 0; i < len_4k; i++) {
275                 #ifndef HDMI_VERSION_2
276                         vic = buf[cur_offset + i] & 0x7f;
277                         if (vic > 0 && vic < 5)
278                                 vic = (vic == 4) ? 98 : (96 - vic);
279                         hdmi_edid_debug("[EDID-CEA] %02x VID %d native %d\n",
280                                         buf[cur_offset + i],
281                                         vic,
282                                         buf[cur_offset + i] >> 7);
283                 #else
284                         vic = buf[cur_offset + i] & 0xff;
285                         hdmi_edid_debug("[EDID-CEA] %02x VID %d native %d\n",
286                                         buf[cur_offset + i], vic);
287                 #endif
288                         if (vic) {
289                                 mode = hdmi_vic_to_videomode(vic);
290                                 if (mode)
291                                         hdmi_add_videomode(mode,
292                                                            &pedid->modelist);
293                         }
294                 }
295                 cur_offset += i;
296         }
297
298 /* TODO Daisen wait to add
299         if (count >= cur_offset && pedid->support_3d && len_3d > 0) {
300
301         }
302 */
303         return E_HDMI_EDID_SUCCESS;
304 }
305
306 /* Parse CEA 861 Serial Extension. */
307 static int hdmi_edid_parse_extensions_cea(unsigned char *buf,
308                                           struct hdmi_edid *pedid)
309 {
310         unsigned int ddc_offset, native_dtd_num, cur_offset = 4;
311         unsigned int underscan_support, baseaudio_support;
312         unsigned int tag;
313
314         if (buf == NULL)
315                 return E_HDMI_EDID_PARAM;
316
317         /* Check ces extension version */
318         if (buf[1] != 3) {
319                 hdmi_edid_error("[EDID-CEA] error version.\n");
320                 return E_HDMI_EDID_VERSION;
321         }
322
323         ddc_offset = buf[2];
324         underscan_support = (buf[3] >> 7) & 0x01;
325         baseaudio_support = (buf[3] >> 6) & 0x01;
326         pedid->ycbcr444 = (buf[3] >> 5) & 0x01;
327         pedid->ycbcr422 = (buf[3] >> 4) & 0x01;
328         native_dtd_num = buf[3] & 0x0F;
329         pedid->base_audio_support = baseaudio_support;
330
331         /* Parse data block */
332         while (cur_offset < ddc_offset) {
333                 tag = buf[cur_offset] >> 5;
334                 switch (tag) {
335                 case 0x02:      /* Video Data Block */
336                         hdmi_edid_debug("[EDID-CEA] It is a Video Data Block.\n");
337                         hdmi_edid_get_cea_svd(buf + cur_offset, pedid);
338                         break;
339                 case 0x01:      /* Audio Data Block */
340                         hdmi_edid_debug("[EDID-CEA] It is a Audio Data Block.\n");
341                         hdmi_edid_parse_cea_sad(buf + cur_offset, pedid);
342                         break;
343                 case 0x04:      /* Speaker Allocation Data Block */
344                         hdmi_edid_debug("[EDID-CEA] It is a Speaker Allocation Data Block.\n");
345                         break;
346                 case 0x03:      /* Vendor Specific Data Block */
347                         hdmi_edid_debug("[EDID-CEA] It is a Vendor Specific Data Block.\n");
348                         hdmi_edid_parse_cea_sdb(buf + cur_offset, pedid);
349                         break;
350                 case 0x05:      /* VESA DTC Data Block */
351                         hdmi_edid_debug("[EDID-CEA] It is a VESA DTC Data Block.\n");
352                         break;
353                 case 0x07:      /* Use Extended Tag */
354                         hdmi_edid_debug("[EDID-CEA] It is a Use Extended Tag Data Block.\n");
355                         break;
356                 default:
357                         hdmi_edid_error("[EDID-CEA] unkowned data block tag.\n");
358                         break;
359                 }
360                 cur_offset += (buf[cur_offset] & 0x1F) + 1;
361         }
362 #if 1
363 {
364         /* Parse DTD */
365         struct fb_videomode *vmode = kmalloc(sizeof(struct fb_videomode),
366                                              GFP_KERNEL);
367         if (vmode == NULL)
368                 return E_HDMI_EDID_SUCCESS;
369         /* buf[126] = 0 and buf[127] = checksum */
370         while (ddc_offset < HDMI_EDID_BLOCK_SIZE - 2) {
371                 if (!buf[ddc_offset] && !buf[ddc_offset + 1])
372                         break;
373                 memset(vmode, 0, sizeof(struct fb_videomode));
374                 hdmi_edid_parse_dtd(buf + ddc_offset, vmode);
375                 hdmi_add_videomode(vmode, &pedid->modelist);
376                 ddc_offset += 18;
377         }
378         kfree(vmode);
379 }
380 #endif
381         return E_HDMI_EDID_SUCCESS;
382 }
383
384 static int hdmi_edid_parse_extensions(unsigned char *buf,
385                                       struct hdmi_edid *pedid)
386 {
387         int rc;
388
389         if (buf == NULL || pedid == NULL)
390                 return E_HDMI_EDID_PARAM;
391
392         /* Checksum */
393         rc = hdmi_edid_checksum(buf);
394         if (rc != E_HDMI_EDID_SUCCESS) {
395                 hdmi_edid_error("[EDID] extensions block checksum error\n");
396                 return E_HDMI_EDID_CHECKSUM;
397         }
398
399         switch (buf[0]) {
400         case 0xF0:
401                 hdmi_edid_debug("[EDID-EXTEND] It is a extensions block map.\n");
402                 break;
403         case 0x02:
404                 hdmi_edid_debug("[EDID-EXTEND] It is a  CEA 861 Series Extension.\n");
405                 hdmi_edid_parse_extensions_cea(buf, pedid);
406                 break;
407         case 0x10:
408                 hdmi_edid_debug("[EDID-EXTEND] It is a Video Timing Block Extension.\n");
409                 break;
410         case 0x40:
411                 hdmi_edid_debug("[EDID-EXTEND] It is a Display Information Extension.\n");
412                 break;
413         case 0x50:
414                 hdmi_edid_debug("[EDID-EXTEND] It is a Localized String Extension.\n");
415                 break;
416         case 0x60:
417                 hdmi_edid_debug("[EDID-EXTEND] It is a Digital Packet Video Link Extension.\n");
418                 break;
419         default:
420                 hdmi_edid_error("[EDID-EXTEND] Unkowned extension.\n");
421                 return E_HDMI_EDID_UNKOWNDATA;
422         }
423
424         return E_HDMI_EDID_SUCCESS;
425 }
426
427
428 int hdmi_sys_parse_edid(struct hdmi *hdmi)
429 {
430         struct hdmi_edid *pedid;
431         unsigned char *buff = NULL;
432         int rc = HDMI_ERROR_SUCESS, extendblock = 0, i;
433
434         if (hdmi == NULL)
435                 return HDMI_ERROR_FALSE;
436
437         pedid = &(hdmi->edid);
438         memset(pedid, 0, sizeof(struct hdmi_edid));
439         INIT_LIST_HEAD(&pedid->modelist);
440
441         buff = kmalloc(HDMI_EDID_BLOCK_SIZE, GFP_KERNEL);
442         if (buff == NULL) {
443                 hdmi_dbg(hdmi->dev,
444                          "[%s] can not allocate memory for edid buff.\n",
445                          __func__);
446                 return -1;
447         }
448
449         /* Read base block edid. */
450         memset(buff, 0 , HDMI_EDID_BLOCK_SIZE);
451         rc = hdmi->read_edid(hdmi, 0, buff);
452         if (rc) {
453                 dev_err(hdmi->dev, "[HDMI] read edid base block error\n");
454                 goto out;
455         }
456         rc = hdmi_edid_parse_base(buff, &extendblock, pedid);
457         if (rc) {
458                 dev_err(hdmi->dev, "[HDMI] parse edid base block error\n");
459                 goto out;
460         }
461         for (i = 1; i < extendblock + 1; i++) {
462                 memset(buff, 0 , HDMI_EDID_BLOCK_SIZE);
463                 rc = hdmi->read_edid(hdmi, i, buff);
464                 if (rc) {
465                         printk("[HDMI] read edid block %d error\n", i);
466                         goto out;
467                 }
468                 rc = hdmi_edid_parse_extensions(buff, pedid);
469                 if (rc) {
470                         dev_err(hdmi->dev, "[HDMI] parse edid block %d error\n",
471                                 i);
472                         continue;
473                 }
474         }
475 out:
476         kfree(buff);
477         rc = hdmi_ouputmode_select(hdmi, rc);
478         return rc;
479 }