1 #include "rockchip-hdmi.h"
2 #include "../../edid.h"
7 #define EDBG(format, ...)
11 E_HDMI_EDID_SUCCESS = 0,
16 E_HDMI_EDID_UNKOWNDATA,
20 static int hdmi_edid_checksum(unsigned char *buf)
25 for (i = 0; i < HDMI_EDID_BLOCK_SIZE; i++)
31 return E_HDMI_EDID_SUCCESS;
33 return E_HDMI_EDID_CHECKSUM;
37 @Des Parse Detail Timing Descriptor.
38 @Param buf : pointer to DTD data.
39 @Param pvic: VIC of DTD descripted.
41 static int hdmi_edid_parse_dtd(unsigned char *block, struct fb_videomode *mode)
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 -
53 mode->lower_margin = V_SYNC_OFFSET;
54 mode->hsync_len = H_SYNC_WIDTH;
55 mode->vsync_len = V_SYNC_WIDTH;
57 mode->sync |= FB_SYNC_HOR_HIGH_ACT;
59 mode->sync |= FB_SYNC_VERT_HIGH_ACT;
60 mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
61 (V_ACTIVE + V_BLANKING));
64 mode->upper_margin *= 2;
65 mode->lower_margin *= 2;
67 mode->vmode |= FB_VMODE_INTERLACED;
69 mode->flag = FB_MODE_IS_DETAILED;
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;
83 int hdmi_edid_parse_base(unsigned char *buf,
84 int *extend_num, struct hdmi_edid *pedid)
88 if (buf == NULL || extend_num == NULL)
89 return E_HDMI_EDID_PARAM;
91 /* Check first 8 byte to ensure it is an edid base block. */
100 pr_err("[EDID] check header error\n");
101 return E_HDMI_EDID_HEAD;
104 *extend_num = buf[0x7e];
106 EDBG("[EDID] extend block num is %d\n", buf[0x7e]);
110 rc = hdmi_edid_checksum(buf);
111 if (rc != E_HDMI_EDID_SUCCESS) {
112 pr_err("[EDID] base block checksum error\n");
113 return E_HDMI_EDID_CHECKSUM;
116 pedid->specs = kzalloc(sizeof(*pedid->specs), GFP_KERNEL);
117 if (pedid->specs == NULL)
118 return E_HDMI_EDID_NOMEMORY;
120 fb_edid_to_monspecs(buf, pedid->specs);
122 return E_HDMI_EDID_SUCCESS;
125 /* Parse CEA Short Video Descriptor */
126 static int hdmi_edid_get_cea_svd(unsigned char *buf, struct hdmi_edid *pedid)
130 count = buf[0] & 0x1F;
131 for (i = 0; i < count; i++) {
132 EDBG("[CEA] %02x VID %d native %d\n",
133 buf[1 + i], buf[1 + i] & 0x7f, buf[1 + i] >> 7);
134 vic = buf[1 + i] & 0x7f;
135 hdmi_add_vic(vic, &pedid->modelist);
138 struct list_head *pos;
139 struct display_modelist *modelist;
141 list_for_each(pos, &pedid->modelist) {
142 modelist = list_entry(pos, struct display_modelist, list);
143 pr_info("%s vic %d\n", __FUNCTION__, modelist->vic);
148 /* Parse CEA Short Audio Descriptor */
149 static int hdmi_edid_parse_cea_sad(unsigned char *buf, struct hdmi_edid *pedid)
153 count = buf[0] & 0x1F;
154 pedid->audio = kmalloc((count/3)*sizeof(struct hdmi_audio), GFP_KERNEL);
155 if (pedid->audio == NULL)
156 return E_HDMI_EDID_NOMEMORY;
158 pedid->audio_num = count/3;
159 for (i = 0; i < pedid->audio_num; i++) {
160 pedid->audio[i].type = (buf[1 + i*3] >> 3) & 0x0F;
161 pedid->audio[i].channel = (buf[1 + i*3] & 0x07) + 1;
162 pedid->audio[i].rate = buf[1 + i*3 + 1];
163 if (pedid->audio[i].type == HDMI_AUDIO_LPCM)
164 pedid->audio[i].word_length = buf[1 + i*3 + 2];
166 /* pr_info("type %d channel %d rate %d word length %d\n",
167 pedid->audio[i].type, pedid->audio[i].channel,
168 pedid->audio[i].rate, pedid->audio[i].word_length);
170 return E_HDMI_EDID_SUCCESS;
173 static int hdmi_edid_parse_3dinfo(unsigned char *buf, struct list_head *head)
175 int i, j, len = 0, format_3d, vic_mask;
176 unsigned char offset = 2, vic_2d, structure_3d;
177 struct list_head *pos;
178 struct display_modelist *modelist;
181 len = (buf[1] & 0xe0) >> 5;
182 for (i = 0; i < len; i++) {
184 hdmi_add_vic((96 - buf[offset++]), head);
190 len += (buf[1] & 0x1F) + 2;
191 if (((buf[0] & 0x60) == 0x40) || ((buf[0] & 0x60) == 0x20)) {
192 format_3d = buf[offset++] << 8;
193 format_3d |= buf[offset++];
194 if ((buf[0] & 0x60) == 0x20) {
197 vic_mask = buf[offset++] << 8;
198 vic_mask |= buf[offset++];
205 for (i = 0; i < 16; i++) {
206 if (vic_mask & (1 << i)) {
208 for (pos = (head)->next; pos != (head);
212 list_entry(pos, struct display_modelist, list);
213 modelist->format_3d = format_3d;
219 while (offset < len) {
220 vic_2d = (buf[offset] & 0xF0) >> 4;
221 structure_3d = (buf[offset++] & 0x0F);
223 for (pos = (head)->next; pos != (head);
228 list_entry(pos, struct display_modelist, list);
229 modelist->format_3d |=
231 if (structure_3d & 0x08)
232 modelist->detail_3d =
233 (buf[offset++] & 0xF0) >> 4;
238 /* mandatory formats */
239 for (pos = (head)->next; pos != (head); pos = pos->next) {
240 modelist = list_entry(pos,
241 struct display_modelist,
243 if (modelist->vic == HDMI_1920X1080P_24HZ ||
244 modelist->vic == HDMI_1280X720P_60HZ ||
245 modelist->vic == HDMI_1280X720P_50HZ) {
246 modelist->format_3d |=
247 (1 << HDMI_3D_FRAME_PACKING) |
248 (1 << HDMI_3D_TOP_BOOTOM);
249 } else if (modelist->vic == HDMI_1920X1080I_60HZ ||
250 modelist->vic == HDMI_1920X1080I_50HZ) {
251 modelist->format_3d |=
252 (1 << HDMI_3D_SIDE_BY_SIDE_HALF);
259 static int hdmi_edmi_parse_vsdb(unsigned char *buf, struct hdmi_edid *pedid,
260 int cur_offset, int IEEEOUI)
262 int count, buf_offset;
264 count = buf[cur_offset] & 0x1F;
267 pedid->sink_hdmi = 1;
268 pedid->cecaddress = buf[cur_offset + 5];
269 pedid->cecaddress |= buf[cur_offset + 4] << 8;
270 EDBG("[CEA] CEC Physical addres is 0x%08x.\n",
273 pedid->deepcolor = (buf[cur_offset + 6] >> 3) & 0x0F;
275 pedid->maxtmdsclock = buf[cur_offset + 7] * 5000000;
276 EDBG("[CEA] maxtmdsclock is %d.\n",
277 pedid->maxtmdsclock);
280 pedid->fields_present = buf[cur_offset + 8];
281 EDBG("[CEA] fields_present is 0x%02x.\n",
282 pedid->fields_present);
284 buf_offset = cur_offset + 9;
285 if (pedid->fields_present & 0x80) {
286 pedid->video_latency = buf[buf_offset++];
287 pedid->audio_latency = buf[buf_offset++];
289 if (pedid->fields_present & 0x40) {
290 pedid->interlaced_video_latency = buf[buf_offset++];
291 pedid->interlaced_audio_latency = buf[buf_offset++];
293 if (pedid->fields_present & 0x20) {
294 hdmi_edid_parse_3dinfo(buf + buf_offset,
299 pedid->sink_hdmi = 1;
301 pedid->hf_vsdb_version = buf[cur_offset + 4];
302 switch (pedid->hf_vsdb_version) {
303 case 1:/*compliant with HDMI Specification 2.0*/
305 pedid->maxtmdsclock =
306 buf[cur_offset + 5] * 5000000;
307 EDBG("[CEA] maxtmdsclock is %d.\n",
308 pedid->maxtmdsclock);
311 pedid->scdc_present = buf[cur_offset+6] >> 7;
313 (buf[cur_offset+6]&0x40) >> 6;
314 pedid->lte_340mcsc_scramble =
315 (buf[cur_offset+6]&0x08) >> 3;
316 pedid->independent_view =
317 (buf[cur_offset+6]&0x04) >> 2;
319 (buf[cur_offset+6]&0x02) >> 1;
320 pedid->osd_disparity_3d =
321 buf[cur_offset+6] & 0x01;
324 pedid->deepcolor = buf[cur_offset+7]&0x7;
325 EDBG("[CEA] deepcolor is %d.\n",
330 pr_info("hf_vsdb_version = %d\n",
331 pedid->hf_vsdb_version);
336 pr_info("IEEOUT = 0x%x\n", IEEEOUI);
342 static void hdmi_edid_parse_yuv420cmdb(unsigned char *buf, int count,
343 struct list_head *head)
345 struct list_head *pos;
346 struct display_modelist *modelist;
347 int i, j, yuv420_mask, vic;
349 for (i = 0; i < count - 1; i++) {
350 EDBG("vic which support yuv420 mode is %x\n", buf[i]);
351 yuv420_mask |= buf[i] << (8 * i);
353 for (i = 0; i < 32; i++) {
354 if (yuv420_mask & (1 << i)) {
356 for (pos = head->next; pos != (head); pos = pos->next) {
359 list_entry(pos, struct display_modelist, list);
360 vic = modelist->vic |
362 hdmi_add_vic(vic, head);
370 /* Parse CEA 861 Serial Extension. */
371 static int hdmi_edid_parse_extensions_cea(unsigned char *buf,
372 struct hdmi_edid *pedid)
374 unsigned int ddc_offset, native_dtd_num, cur_offset = 4;
375 unsigned int tag, IEEEOUI = 0, count, i;
376 /* unsigned int underscan_support, baseaudio_support; */
379 return E_HDMI_EDID_PARAM;
381 /* Check ces extension version */
383 pr_err("[CEA] error version.\n");
384 return E_HDMI_EDID_VERSION;
388 /* underscan_support = (buf[3] >> 7) & 0x01;
389 */ pedid->baseaudio_support = (buf[3] >> 6) & 0x01;
390 pedid->ycbcr444 = (buf[3] >> 5) & 0x01;
391 pedid->ycbcr422 = (buf[3] >> 4) & 0x01;
392 native_dtd_num = buf[3] & 0x0F;
393 /* EDBG("[CEA] ddc_offset %d underscan_support %d
394 baseaudio_support %d yuv_support %d
395 native_dtd_num %d\n",
396 ddc_offset, underscan_support, baseaudio_support,
397 yuv_support, native_dtd_num);
398 */ /* Parse data block */
399 while (cur_offset < ddc_offset) {
400 tag = buf[cur_offset] >> 5;
401 count = buf[cur_offset] & 0x1F;
403 case 0x02: /* Video Data Block */
404 EDBG("[CEA] Video Data Block.\n");
405 hdmi_edid_get_cea_svd(buf + cur_offset, pedid);
407 case 0x01: /* Audio Data Block */
408 EDBG("[CEA] Audio Data Block.\n");
409 hdmi_edid_parse_cea_sad(buf + cur_offset, pedid);
411 case 0x04: /* Speaker Allocation Data Block */
412 EDBG("[CEA] Speaker Allocatio Data Block.\n");
414 case 0x03: /* Vendor Specific Data Block */
415 EDBG("[CEA] Vendor Specific Data Block.\n");
417 IEEEOUI = buf[cur_offset + 3];
419 IEEEOUI += buf[cur_offset + 2];
421 IEEEOUI += buf[cur_offset + 1];
422 EDBG("[CEA] IEEEOUI is 0x%08x.\n", IEEEOUI);
424 hdmi_edmi_parse_vsdb(buf, pedid,
425 cur_offset, IEEEOUI);
427 case 0x05: /* VESA DTC Data Block */
428 EDBG("[CEA] VESA DTC Data Block.\n");
430 case 0x07: /* Use Extended Tag */
431 EDBG("[CEA] Use Extended Tag Data Block %02x.\n",
432 buf[cur_offset + 1]);
433 switch (buf[cur_offset + 1]) {
435 EDBG("[CEA] Video Capability Data Block\n");
436 EDBG("value is %02x\n", buf[cur_offset + 2]);
439 EDBG("[CEA] Colorimetry Data Block\n");
440 EDBG("value is %02x\n", buf[cur_offset + 2]);
443 EDBG("[CEA] YCBCR 4:2:0 Video Data Block\n");
444 for (i = 0; i < count - 1; i++) {
446 buf[cur_offset + 2 + i]);
448 IEEEOUI = buf[cur_offset + 2 + i] |
450 hdmi_add_vic(IEEEOUI,
455 EDBG("[CEA] YCBCR 4:2:0 Capability Map Data\n");
456 hdmi_edid_parse_yuv420cmdb(&buf[cur_offset+2],
464 pr_err("[CEA] unkowned data block tag.\n");
467 cur_offset += (buf[cur_offset] & 0x1F) + 1;
472 struct fb_videomode *vmode =
473 kmalloc(sizeof(struct fb_videomode), GFP_KERNEL);
476 return E_HDMI_EDID_SUCCESS;
477 while (ddc_offset < HDMI_EDID_BLOCK_SIZE - 2) {
478 if (!buf[ddc_offset] && !buf[ddc_offset + 1])
480 memset(vmode, 0, sizeof(struct fb_videomode));
481 hdmi_edid_parse_dtd(buf + ddc_offset, vmode);
482 hdmi_add_vic(hdmi_videomode_to_vic(vmode), &pedid->modelist);
488 return E_HDMI_EDID_SUCCESS;
491 int hdmi_edid_parse_extensions(unsigned char *buf, struct hdmi_edid *pedid)
495 if (buf == NULL || pedid == NULL)
496 return E_HDMI_EDID_PARAM;
499 rc = hdmi_edid_checksum(buf);
500 if (rc != E_HDMI_EDID_SUCCESS) {
501 pr_err("[EDID] extensions block checksum error\n");
502 return E_HDMI_EDID_CHECKSUM;
507 EDBG("[EDID-EXTEND] Iextensions block map.\n");
510 EDBG("[EDID-EXTEND] CEA 861 Series Extension.\n");
511 hdmi_edid_parse_extensions_cea(buf, pedid);
514 EDBG("[EDID-EXTEND] Video Timing Block Extension.\n");
517 EDBG("[EDID-EXTEND] Display Information Extension.\n");
520 EDBG("[EDID-EXTEND] Localized String Extension.\n");
523 EDBG("[EDID-EXTEND] Digital Packet Video Link Extension.\n");
526 pr_err("[EDID-EXTEND] Unkowned Extension.\n");
527 return E_HDMI_EDID_UNKOWNDATA;
530 return E_HDMI_EDID_SUCCESS;