Merge tag 'lsk-v3.10-android-14.07' 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         if (count > 5) {
227                 pedid->deepcolor = (buf[6] >> 3) & 0x0F;
228                 supports_ai = buf[6] >> 7;
229                 dc_48bit = (buf[6] >> 6) & 0x1;
230                 dc_36bit = (buf[6] >> 5) & 0x1;
231                 dc_30bit = (buf[6] >> 4) & 0x1;
232                 dc_y444 = (buf[6] >> 3) & 0x1;
233                 hdmi_edid_debug("[EDID-CEA] supports_ai %d\n"
234                         "dc_48bit %d dc_36bit %d dc_30bit %d dc_y444 %d\n",
235                         supports_ai,
236                         dc_48bit, dc_36bit, dc_30bit, dc_y444);
237         }
238         if (count > 6)
239                 pedid->maxtmdsclock = buf[7] * 5000000;
240
241         if (count > 7) {
242                 pedid->latency_fields_present = (buf[8] & 0x80) ? 1 : 0;
243                 pedid->i_latency_fields_present = (buf[8] & 0x40) ? 1 : 0;
244                 pedid->video_present = (buf[8] & 0x20) ? 1 : 0;
245         }
246
247         cur_offset = 9;
248         if (count >= cur_offset) {
249                 if (pedid->latency_fields_present == 1) {
250                         pedid->video_latency = buf[cur_offset++];
251                         pedid->audio_latency = buf[cur_offset++];
252                 }
253                 if (count >= cur_offset && pedid->i_latency_fields_present) {
254                         pedid->interlaced_video_latency = buf[cur_offset++];
255                         pedid->interlaced_audio_latency = buf[cur_offset++];
256                 }
257         }
258
259         if (pedid->video_present == 0)
260                 return E_HDMI_EDID_SUCCESS;
261
262         if (count >= cur_offset) {
263                 pedid->support_3d = (buf[cur_offset++] & 0x80) ? 1 : 0;
264
265                 len_4k = (buf[cur_offset] >> 5) & 0x07;
266                 len_3d = buf[cur_offset] & 0x1F;
267                 cur_offset++;
268         }
269         if (count >= cur_offset && len_4k > 0) {
270                 for (i = 0; i < len_4k; i++) {
271                 #ifndef HDMI_VERSION_2
272                         vic = buf[cur_offset + i] & 0x7f;
273                         if (vic > 0 && vic < 5)
274                                 vic = (vic == 4) ? 98 : (96 - vic);
275                         hdmi_edid_debug("[EDID-CEA] %02x VID %d native %d\n",
276                                         buf[cur_offset + i],
277                                         vic,
278                                         buf[cur_offset + i] >> 7);
279                 #else
280                         vic = buf[cur_offset + i] & 0xff;
281                         hdmi_edid_debug("[EDID-CEA] %02x VID %d native %d\n",
282                                         buf[cur_offset + i], vic);
283                 #endif
284                         if (vic) {
285                                 mode = hdmi_vic_to_videomode(vic);
286                                 if (mode)
287                                         hdmi_add_videomode(mode,
288                                                            &pedid->modelist);
289                         }
290                 }
291                 cur_offset += i;
292         }
293
294 /* TODO Daisen wait to add
295         if (count >= cur_offset && pedid->support_3d && len_3d > 0) {
296
297         }
298 */
299         return E_HDMI_EDID_SUCCESS;
300 }
301
302 /* Parse CEA 861 Serial Extension. */
303 static int hdmi_edid_parse_extensions_cea(unsigned char *buf,
304                                           struct hdmi_edid *pedid)
305 {
306         unsigned int ddc_offset, native_dtd_num, cur_offset = 4;
307         unsigned int underscan_support, baseaudio_support;
308         unsigned int tag;
309
310         if (buf == NULL)
311                 return E_HDMI_EDID_PARAM;
312
313         /* Check ces extension version */
314         if (buf[1] != 3) {
315                 hdmi_edid_error("[EDID-CEA] error version.\n");
316                 return E_HDMI_EDID_VERSION;
317         }
318
319         ddc_offset = buf[2];
320         underscan_support = (buf[3] >> 7) & 0x01;
321         baseaudio_support = (buf[3] >> 6) & 0x01;
322         pedid->ycbcr444 = (buf[3] >> 5) & 0x01;
323         pedid->ycbcr422 = (buf[3] >> 4) & 0x01;
324         native_dtd_num = buf[3] & 0x0F;
325         pedid->base_audio_support = baseaudio_support;
326
327         /* Parse data block */
328         while (cur_offset < ddc_offset) {
329                 tag = buf[cur_offset] >> 5;
330                 switch (tag) {
331                 case 0x02:      /* Video Data Block */
332                         hdmi_edid_debug("[EDID-CEA] It is a Video Data Block.\n");
333                         hdmi_edid_get_cea_svd(buf + cur_offset, pedid);
334                         break;
335                 case 0x01:      /* Audio Data Block */
336                         hdmi_edid_debug("[EDID-CEA] It is a Audio Data Block.\n");
337                         hdmi_edid_parse_cea_sad(buf + cur_offset, pedid);
338                         break;
339                 case 0x04:      /* Speaker Allocation Data Block */
340                         hdmi_edid_debug("[EDID-CEA] It is a Speaker Allocation Data Block.\n");
341                         break;
342                 case 0x03:      /* Vendor Specific Data Block */
343                         hdmi_edid_debug("[EDID-CEA] It is a Vendor Specific Data Block.\n");
344                         hdmi_edid_parse_cea_sdb(buf + cur_offset, pedid);
345                         break;
346                 case 0x05:      /* VESA DTC Data Block */
347                         hdmi_edid_debug("[EDID-CEA] It is a VESA DTC Data Block.\n");
348                         break;
349                 case 0x07:      /* Use Extended Tag */
350                         hdmi_edid_debug("[EDID-CEA] It is a Use Extended Tag Data Block.\n");
351                         break;
352                 default:
353                         hdmi_edid_error("[EDID-CEA] unkowned data block tag.\n");
354                         break;
355                 }
356                 cur_offset += (buf[cur_offset] & 0x1F) + 1;
357         }
358 #if 1
359 {
360         /* Parse DTD */
361         struct fb_videomode *vmode = kmalloc(sizeof(struct fb_videomode),
362                                              GFP_KERNEL);
363         if (vmode == NULL)
364                 return E_HDMI_EDID_SUCCESS;
365         /* buf[126] = 0 and buf[127] = checksum */
366         while (ddc_offset < HDMI_EDID_BLOCK_SIZE - 2) {
367                 if (!buf[ddc_offset] && !buf[ddc_offset + 1])
368                         break;
369                 memset(vmode, 0, sizeof(struct fb_videomode));
370                 hdmi_edid_parse_dtd(buf + ddc_offset, vmode);
371                 hdmi_add_videomode(vmode, &pedid->modelist);
372                 ddc_offset += 18;
373         }
374         kfree(vmode);
375 }
376 #endif
377         return E_HDMI_EDID_SUCCESS;
378 }
379
380 static int hdmi_edid_parse_extensions(unsigned char *buf,
381                                       struct hdmi_edid *pedid)
382 {
383         int rc;
384
385         if (buf == NULL || pedid == NULL)
386                 return E_HDMI_EDID_PARAM;
387
388         /* Checksum */
389         rc = hdmi_edid_checksum(buf);
390         if (rc != E_HDMI_EDID_SUCCESS) {
391                 hdmi_edid_error("[EDID] extensions block checksum error\n");
392                 return E_HDMI_EDID_CHECKSUM;
393         }
394
395         switch (buf[0]) {
396         case 0xF0:
397                 hdmi_edid_debug("[EDID-EXTEND] It is a extensions block map.\n");
398                 break;
399         case 0x02:
400                 hdmi_edid_debug("[EDID-EXTEND] It is a  CEA 861 Series Extension.\n");
401                 hdmi_edid_parse_extensions_cea(buf, pedid);
402                 break;
403         case 0x10:
404                 hdmi_edid_debug("[EDID-EXTEND] It is a Video Timing Block Extension.\n");
405                 break;
406         case 0x40:
407                 hdmi_edid_debug("[EDID-EXTEND] It is a Display Information Extension.\n");
408                 break;
409         case 0x50:
410                 hdmi_edid_debug("[EDID-EXTEND] It is a Localized String Extension.\n");
411                 break;
412         case 0x60:
413                 hdmi_edid_debug("[EDID-EXTEND] It is a Digital Packet Video Link Extension.\n");
414                 break;
415         default:
416                 hdmi_edid_error("[EDID-EXTEND] Unkowned extension.\n");
417                 return E_HDMI_EDID_UNKOWNDATA;
418         }
419
420         return E_HDMI_EDID_SUCCESS;
421 }
422
423
424 int hdmi_sys_parse_edid(struct hdmi *hdmi)
425 {
426         struct hdmi_edid *pedid;
427         unsigned char *buff = NULL;
428         int rc = HDMI_ERROR_SUCESS, extendblock = 0, i;
429
430         if (hdmi == NULL)
431                 return HDMI_ERROR_FALSE;
432
433         pedid = &(hdmi->edid);
434         memset(pedid, 0, sizeof(struct hdmi_edid));
435         INIT_LIST_HEAD(&pedid->modelist);
436
437         buff = kmalloc(HDMI_EDID_BLOCK_SIZE, GFP_KERNEL);
438         if (buff == NULL) {
439                 hdmi_dbg(hdmi->dev,
440                          "[%s] can not allocate memory for edid buff.\n",
441                          __func__);
442                 return -1;
443         }
444
445         /* Read base block edid. */
446         memset(buff, 0 , HDMI_EDID_BLOCK_SIZE);
447         rc = hdmi->read_edid(hdmi, 0, buff);
448         if (rc) {
449                 dev_err(hdmi->dev, "[HDMI] read edid base block error\n");
450                 goto out;
451         }
452         rc = hdmi_edid_parse_base(buff, &extendblock, pedid);
453         if (rc) {
454                 dev_err(hdmi->dev, "[HDMI] parse edid base block error\n");
455                 goto out;
456         }
457         for (i = 1; i < extendblock + 1; i++) {
458                 memset(buff, 0 , HDMI_EDID_BLOCK_SIZE);
459                 rc = hdmi->read_edid(hdmi, i, buff);
460                 if (rc) {
461                         printk("[HDMI] read edid block %d error\n", i);
462                         goto out;
463                 }
464                 rc = hdmi_edid_parse_extensions(buff, pedid);
465                 if (rc) {
466                         dev_err(hdmi->dev, "[HDMI] parse edid block %d error\n",
467                                 i);
468                         continue;
469                 }
470         }
471 out:
472         kfree(buff);
473         rc = hdmi_ouputmode_select(hdmi, rc);
474         return rc;
475 }