Merge tag 'lsk-android-14.05' 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, i;
98
99         if (buf == NULL || extend_num == NULL)
100                 return E_HDMI_EDID_PARAM;
101
102 #ifdef DEBUG
103         for (i = 0; i < HDMI_EDID_BLOCK_SIZE; i++) {
104                 hdmi_edid_debug("%02x ", buf[i]&0xff);
105                 if ((i+1) % 16 == 0)
106                         hdmi_edid_debug("\n");
107         }
108 #endif
109
110         /* Check first 8 byte to ensure it is an edid base block. */
111         if (buf[0] != 0x00 ||
112             buf[1] != 0xFF ||
113             buf[2] != 0xFF ||
114             buf[3] != 0xFF ||
115             buf[4] != 0xFF ||
116             buf[5] != 0xFF ||
117             buf[6] != 0xFF ||
118             buf[7] != 0x00) {
119                 hdmi_edid_error("[EDID] check header error\n");
120                 return E_HDMI_EDID_HEAD;
121         }
122
123         *extend_num = buf[0x7e];
124 #ifdef DEBUG
125         hdmi_edid_debug("[EDID] extend block num is %d\n", buf[0x7e]);
126 #endif
127
128         /* Checksum */
129         rc = hdmi_edid_checksum(buf);
130         if (rc != E_HDMI_EDID_SUCCESS) {
131                 hdmi_edid_error("[EDID] base block checksum error\n");
132                 return E_HDMI_EDID_CHECKSUM;
133         }
134
135         pedid->specs = kzalloc(sizeof(struct fb_monspecs), GFP_KERNEL);
136         if (pedid->specs == NULL)
137                 return E_HDMI_EDID_NOMEMORY;
138
139         fb_edid_to_monspecs(buf, pedid->specs);
140
141         return E_HDMI_EDID_SUCCESS;
142 }
143
144 /* Parse CEA Short Video Descriptor */
145 static int hdmi_edid_get_cea_svd(unsigned char *buf, struct hdmi_edid *pedid)
146 {
147         const struct fb_videomode *mode;
148         int count, i, j, vic;
149
150         count = buf[0] & 0x1F;
151         for (i = 0; i < count; i++) {
152                 hdmi_edid_debug("[EDID-CEA] %02x VID %d native %d\n",
153                                 buf[1 + i],
154                                 buf[1 + i] & 0x7f,
155                                 buf[1 + i] >> 7);
156         #ifndef HDMI_VERSION_2
157                 vic = buf[1 + i] & 0x7f;
158         #else
159                 vic = buf[1 + i] & 0xff;
160         #endif
161                 for (j = 0; j < ARRAY_SIZE(double_aspect_vic); j++) {
162                         if (vic == double_aspect_vic[j]) {
163                                 vic--;
164                                 break;
165                         }
166                 }
167                 if (vic) {
168                         mode = hdmi_vic_to_videomode(vic);
169                         if (mode)
170                                 hdmi_add_videomode(mode, &pedid->modelist);
171                 }
172         }
173         return 0;
174 }
175
176 /* Parse CEA Short Audio Descriptor */
177 static int hdmi_edid_parse_cea_sad(unsigned char *buf, struct hdmi_edid *pedid)
178 {
179         int i, count;
180
181         count = buf[0] & 0x1F;
182         pedid->audio = kmalloc((count / 3) * sizeof(struct hdmi_audio),
183                                 GFP_KERNEL);
184         if (pedid->audio == NULL)
185                 return E_HDMI_EDID_NOMEMORY;
186
187         pedid->audio_num = count / 3;
188         for (i = 0; i < pedid->audio_num; i++) {
189                 pedid->audio[i].type = (buf[1 + i * 3] >> 3) & 0x0F;
190                 pedid->audio[i].channel = (buf[1 + i * 3] & 0x07) + 1;
191                 pedid->audio[i].rate = buf[1 + i * 3 + 1];
192                 if (pedid->audio[i].type == HDMI_AUDIO_LPCM)    /* LPCM */
193                         pedid->audio[i].word_length = buf[1 + i * 3 + 2];
194 /*
195                 printk("[EDID-CEA] type %d channel %d rate %d word length %d\n",
196                         pedid->audio[i].type, pedid->audio[i].channel,
197                         pedid->audio[i].rate, pedid->audio[i].word_length);
198 */
199         }
200         return E_HDMI_EDID_SUCCESS;
201 }
202
203 /* Parse CEA Vendor Specific Data Block */
204 static int hdmi_edid_parse_cea_sdb(unsigned char *buf, struct hdmi_edid *pedid)
205 {
206         unsigned int count = 0, cur_offset = 0, i = 0;
207         unsigned int IEEEOUI = 0;
208         unsigned int supports_ai, dc_48bit, dc_36bit, dc_30bit, dc_y444;
209         unsigned int len_3d, len_4k;
210         unsigned char vic = 0;
211         const struct fb_videomode *mode;
212
213         count = buf[0] & 0x1F;
214         IEEEOUI = buf[3];
215         IEEEOUI <<= 8;
216         IEEEOUI += buf[2];
217         IEEEOUI <<= 8;
218         IEEEOUI += buf[1];
219         hdmi_edid_debug("[EDID-CEA] IEEEOUI is 0x%08x.\n", IEEEOUI);
220         if (IEEEOUI == 0x0c03)
221                 pedid->sink_hdmi = 1;
222
223         if (count > 5) {
224                 pedid->deepcolor = (buf[6] >> 3) & 0x0F;
225                 supports_ai = buf[6] >> 7;
226                 dc_48bit = (buf[6] >> 6) & 0x1;
227                 dc_36bit = (buf[6] >> 5) & 0x1;
228                 dc_30bit = (buf[6] >> 4) & 0x1;
229                 dc_y444 = (buf[6] >> 3) & 0x1;
230                 hdmi_edid_debug("[EDID-CEA] supports_ai %d\n"
231                         "dc_48bit %d dc_36bit %d dc_30bit %d dc_y444 %d\n",
232                         supports_ai,
233                         dc_48bit, dc_36bit, dc_30bit, dc_y444);
234         }
235         if (count > 6)
236                 pedid->maxtmdsclock = buf[7] * 5000000;
237
238         if (count > 7) {
239                 pedid->latency_fields_present = (buf[8] & 0x80) ? 1 : 0;
240                 pedid->i_latency_fields_present = (buf[8] & 0x40) ? 1 : 0;
241                 pedid->video_present = (buf[8] & 0x20) ? 1 : 0;
242         }
243
244         cur_offset = 9;
245         if (count >= cur_offset) {
246                 if (pedid->latency_fields_present == 1) {
247                         pedid->video_latency = buf[cur_offset++];
248                         pedid->audio_latency = buf[cur_offset++];
249                 }
250                 if (count >= cur_offset && pedid->i_latency_fields_present) {
251                         pedid->interlaced_video_latency = buf[cur_offset++];
252                         pedid->interlaced_audio_latency = buf[cur_offset++];
253                 }
254         }
255
256         if (pedid->video_present == 0)
257                 return E_HDMI_EDID_SUCCESS;
258
259         if (count >= cur_offset) {
260                 pedid->support_3d = (buf[cur_offset++] & 0x80) ? 1 : 0;
261
262                 len_4k = (buf[cur_offset] >> 5) & 0x07;
263                 len_3d = buf[cur_offset] & 0x1F;
264                 cur_offset++;
265         }
266         if (count >= cur_offset && len_4k > 0) {
267                 for (i = 0; i < len_4k; i++) {
268                 #ifndef HDMI_VERSION_2
269                         vic = buf[cur_offset + i] & 0x7f;
270                         if (vic > 0 && vic < 5)
271                                 vic = (vic == 4) ? 98 : (96 - vic);
272                         hdmi_edid_debug("[EDID-CEA] %02x VID %d native %d\n",
273                                         buf[cur_offset + i],
274                                         vic,
275                                         buf[cur_offset + i] >> 7);
276                 #else
277                         vic = buf[cur_offset + i] & 0xff;
278                         hdmi_edid_debug("[EDID-CEA] %02x VID %d native %d\n",
279                                         buf[cur_offset + i], vic);
280                 #endif
281                         if (vic) {
282                                 mode = hdmi_vic_to_videomode(vic);
283                                 if (mode)
284                                         hdmi_add_videomode(mode,
285                                                            &pedid->modelist);
286                         }
287                 }
288                 cur_offset += i;
289         }
290
291 /* TODO Daisen wait to add
292         if (count >= cur_offset && pedid->support_3d && len_3d > 0) {
293
294         }
295 */
296         return E_HDMI_EDID_SUCCESS;
297 }
298
299 /* Parse CEA 861 Serial Extension. */
300 static int hdmi_edid_parse_extensions_cea(unsigned char *buf,
301                                           struct hdmi_edid *pedid)
302 {
303         unsigned int ddc_offset, native_dtd_num, cur_offset = 4;
304         unsigned int underscan_support, baseaudio_support;
305         unsigned int tag;
306
307         if (buf == NULL)
308                 return E_HDMI_EDID_PARAM;
309
310         /* Check ces extension version */
311         if (buf[1] != 3) {
312                 hdmi_edid_error("[EDID-CEA] error version.\n");
313                 return E_HDMI_EDID_VERSION;
314         }
315
316         ddc_offset = buf[2];
317         underscan_support = (buf[3] >> 7) & 0x01;
318         baseaudio_support = (buf[3] >> 6) & 0x01;
319         pedid->ycbcr444 = (buf[3] >> 5) & 0x01;
320         pedid->ycbcr422 = (buf[3] >> 4) & 0x01;
321         native_dtd_num = buf[3] & 0x0F;
322         pedid->base_audio_support = baseaudio_support;
323
324         /* Parse data block */
325         while (cur_offset < ddc_offset) {
326                 tag = buf[cur_offset] >> 5;
327                 switch (tag) {
328                 case 0x02:      /* Video Data Block */
329                         hdmi_edid_debug("[EDID-CEA] It is a Video Data Block.\n");
330                         hdmi_edid_get_cea_svd(buf + cur_offset, pedid);
331                         break;
332                 case 0x01:      /* Audio Data Block */
333                         hdmi_edid_debug("[EDID-CEA] It is a Audio Data Block.\n");
334                         hdmi_edid_parse_cea_sad(buf + cur_offset, pedid);
335                         break;
336                 case 0x04:      /* Speaker Allocation Data Block */
337                         hdmi_edid_debug("[EDID-CEA] It is a Speaker Allocation Data Block.\n");
338                         break;
339                 case 0x03:      /* Vendor Specific Data Block */
340                         hdmi_edid_debug("[EDID-CEA] It is a Vendor Specific Data Block.\n");
341                         hdmi_edid_parse_cea_sdb(buf + cur_offset, pedid);
342                         break;
343                 case 0x05:      /* VESA DTC Data Block */
344                         hdmi_edid_debug("[EDID-CEA] It is a VESA DTC Data Block.\n");
345                         break;
346                 case 0x07:      /* Use Extended Tag */
347                         hdmi_edid_debug("[EDID-CEA] It is a Use Extended Tag Data Block.\n");
348                         break;
349                 default:
350                         hdmi_edid_error("[EDID-CEA] unkowned data block tag.\n");
351                         break;
352                 }
353                 cur_offset += (buf[cur_offset] & 0x1F) + 1;
354         }
355 #if 1
356 {
357         /* Parse DTD */
358         struct fb_videomode *vmode = kmalloc(sizeof(struct fb_videomode),
359                                              GFP_KERNEL);
360         if (vmode == NULL)
361                 return E_HDMI_EDID_SUCCESS;
362         /* buf[126] = 0 and buf[127] = checksum */
363         while (ddc_offset < HDMI_EDID_BLOCK_SIZE - 2) {
364                 if (!buf[ddc_offset] && !buf[ddc_offset + 1])
365                         break;
366                 memset(vmode, 0, sizeof(struct fb_videomode));
367                 hdmi_edid_parse_dtd(buf + ddc_offset, vmode);
368                 hdmi_add_videomode(vmode, &pedid->modelist);
369                 ddc_offset += 18;
370         }
371         kfree(vmode);
372 }
373 #endif
374         return E_HDMI_EDID_SUCCESS;
375 }
376
377 static int hdmi_edid_parse_extensions(unsigned char *buf,
378                                       struct hdmi_edid *pedid)
379 {
380         int rc;
381
382         if (buf == NULL || pedid == NULL)
383                 return E_HDMI_EDID_PARAM;
384
385         /* Checksum */
386         rc = hdmi_edid_checksum(buf);
387         if (rc != E_HDMI_EDID_SUCCESS) {
388                 hdmi_edid_error("[EDID] extensions block checksum error\n");
389                 return E_HDMI_EDID_CHECKSUM;
390         }
391
392         switch (buf[0]) {
393         case 0xF0:
394                 hdmi_edid_debug("[EDID-EXTEND] It is a extensions block map.\n");
395                 break;
396         case 0x02:
397                 hdmi_edid_debug("[EDID-EXTEND] It is a  CEA 861 Series Extension.\n");
398                 hdmi_edid_parse_extensions_cea(buf, pedid);
399                 break;
400         case 0x10:
401                 hdmi_edid_debug("[EDID-EXTEND] It is a Video Timing Block Extension.\n");
402                 break;
403         case 0x40:
404                 hdmi_edid_debug("[EDID-EXTEND] It is a Display Information Extension.\n");
405                 break;
406         case 0x50:
407                 hdmi_edid_debug("[EDID-EXTEND] It is a Localized String Extension.\n");
408                 break;
409         case 0x60:
410                 hdmi_edid_debug("[EDID-EXTEND] It is a Digital Packet Video Link Extension.\n");
411                 break;
412         default:
413                 hdmi_edid_error("[EDID-EXTEND] Unkowned extension.\n");
414                 return E_HDMI_EDID_UNKOWNDATA;
415         }
416
417         return E_HDMI_EDID_SUCCESS;
418 }
419
420
421 int hdmi_sys_parse_edid(struct hdmi *hdmi)
422 {
423         struct hdmi_edid *pedid;
424         unsigned char *buff = NULL;
425         int rc = HDMI_ERROR_SUCESS, extendblock = 0, i;
426
427         if (hdmi == NULL)
428                 return HDMI_ERROR_FALSE;
429
430         pedid = &(hdmi->edid);
431         memset(pedid, 0, sizeof(struct hdmi_edid));
432         INIT_LIST_HEAD(&pedid->modelist);
433
434         buff = kmalloc(HDMI_EDID_BLOCK_SIZE, GFP_KERNEL);
435         if (buff == NULL) {
436                 hdmi_dbg(hdmi->dev,
437                          "[%s] can not allocate memory for edid buff.\n",
438                          __func__);
439                 return -1;
440         }
441
442         /* Read base block edid. */
443         memset(buff, 0 , HDMI_EDID_BLOCK_SIZE);
444         rc = hdmi->read_edid(hdmi, 0, buff);
445         if (rc) {
446                 dev_err(hdmi->dev, "[HDMI] read edid base block error\n");
447                 goto out;
448         }
449         rc = hdmi_edid_parse_base(buff, &extendblock, pedid);
450         if (rc) {
451                 dev_err(hdmi->dev, "[HDMI] parse edid base block error\n");
452                 goto out;
453         }
454         for (i = 1; i < extendblock + 1; i++) {
455                 memset(buff, 0 , HDMI_EDID_BLOCK_SIZE);
456                 rc = hdmi->read_edid(hdmi, i, buff);
457                 if (rc) {
458                         printk("[HDMI] read edid block %d error\n", i);
459                         goto out;
460                 }
461                 rc = hdmi_edid_parse_extensions(buff, pedid);
462                 if (rc) {
463                         dev_err(hdmi->dev, "[HDMI] parse edid block %d error\n",
464                                 i);
465                         continue;
466                 }
467         }
468 out:
469         kfree(buff);
470         rc = hdmi_ouputmode_select(hdmi, rc);
471         return rc;
472 }