2 #include "../../edid.h"
\r
4 #define hdmi_edid_error(fmt, ...) \
\r
5 printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
\r
8 #define hdmi_edid_debug(fmt, ...) \
\r
9 printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
\r
11 #define hdmi_edid_debug(fmt, ...)
\r
14 typedef enum HDMI_EDID_ERRORCODE
\r
16 E_HDMI_EDID_SUCCESS = 0,
\r
19 E_HDMI_EDID_CHECKSUM,
\r
20 E_HDMI_EDID_VERSION,
\r
21 E_HDMI_EDID_UNKOWNDATA,
\r
22 E_HDMI_EDID_NOMEMORY
\r
23 }HDMI_EDID_ErrorCode;
\r
25 static const unsigned int double_aspect_vic[] = {3, 7, 9, 11, 13, 15, 18, 22, 24, 26, 28, 30, 36, 38, 43, 45, 49, 51, 53, 55, 57, 59};
\r
26 static int hdmi_edid_checksum(unsigned char *buf)
\r
31 for(i = 0; i < HDMI_EDID_BLOCK_SIZE; i++)
\r
32 checksum += buf[i];
\r
37 return E_HDMI_EDID_SUCCESS;
\r
39 return E_HDMI_EDID_CHECKSUM;
\r
43 @Des Parse Detail Timing Descriptor.
\r
44 @Param buf : pointer to DTD data.
\r
45 @Param pvic: VIC of DTD descripted.
\r
47 static int hdmi_edid_parse_dtd(unsigned char *block, struct fb_videomode *mode)
\r
49 mode->xres = H_ACTIVE;
\r
50 mode->yres = V_ACTIVE;
\r
51 mode->pixclock = PIXEL_CLOCK;
\r
52 // mode->pixclock /= 1000;
\r
53 // mode->pixclock = KHZ2PICOS(mode->pixclock);
\r
54 mode->right_margin = H_SYNC_OFFSET;
\r
55 mode->left_margin = (H_ACTIVE + H_BLANKING) -
\r
56 (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
\r
57 mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
\r
59 mode->lower_margin = V_SYNC_OFFSET;
\r
60 mode->hsync_len = H_SYNC_WIDTH;
\r
61 mode->vsync_len = V_SYNC_WIDTH;
\r
63 mode->sync |= FB_SYNC_HOR_HIGH_ACT;
\r
65 mode->sync |= FB_SYNC_VERT_HIGH_ACT;
\r
66 mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
\r
67 (V_ACTIVE + V_BLANKING));
\r
70 mode->upper_margin *= 2;
\r
71 mode->lower_margin *= 2;
\r
72 mode->vsync_len *= 2;
\r
73 mode->vmode |= FB_VMODE_INTERLACED;
\r
75 mode->flag = FB_MODE_IS_DETAILED;
\r
77 hdmi_edid_debug("<<<<<<<<Detailed Time>>>>>>>>>\n");
\r
78 hdmi_edid_debug("%d KHz Refresh %d Hz", PIXEL_CLOCK/1000, mode->refresh);
\r
79 hdmi_edid_debug("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,
\r
80 H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
\r
81 hdmi_edid_debug("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,
\r
82 V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
\r
83 hdmi_edid_debug("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",
\r
84 (VSYNC_POSITIVE) ? "+" : "-");
\r
85 return E_HDMI_EDID_SUCCESS;
\r
88 static int hdmi_edid_parse_base(unsigned char *buf, int *extend_num, struct hdmi_edid *pedid)
\r
92 if(buf == NULL || extend_num == NULL)
\r
93 return E_HDMI_EDID_PARAM;
\r
96 for(i = 0; i < HDMI_EDID_BLOCK_SIZE; i++)
\r
98 hdmi_edid_debug("%02x ", buf[i]&0xff);
\r
100 hdmi_edid_debug("\n");
\r
104 // Check first 8 byte to ensure it is an edid base block.
\r
105 if( buf[0] != 0x00 ||
\r
114 hdmi_edid_error("[EDID] check header error\n");
\r
115 return E_HDMI_EDID_HEAD;
\r
118 *extend_num = buf[0x7e];
\r
120 hdmi_edid_debug("[EDID] extend block num is %d\n", buf[0x7e]);
\r
124 rc = hdmi_edid_checksum(buf);
\r
125 if( rc != E_HDMI_EDID_SUCCESS)
\r
127 hdmi_edid_error("[EDID] base block checksum error\n");
\r
128 return E_HDMI_EDID_CHECKSUM;
\r
131 pedid->specs = kzalloc(sizeof(struct fb_monspecs), GFP_KERNEL);
\r
132 if(pedid->specs == NULL)
\r
133 return E_HDMI_EDID_NOMEMORY;
\r
135 fb_edid_to_monspecs(buf, pedid->specs);
\r
137 return E_HDMI_EDID_SUCCESS;
\r
140 // Parse CEA Short Video Descriptor
\r
141 static int hdmi_edid_get_cea_svd(unsigned char *buf, struct hdmi_edid *pedid)
\r
143 const struct fb_videomode *mode;
\r
144 int count, i, j, vic;
\r
146 count = buf[0] & 0x1F;
\r
147 for(i = 0; i < count; i++)
\r
149 hdmi_edid_debug("[EDID-CEA] %02x VID %d native %d\n", buf[1 + i], buf[1 + i] & 0x7f, buf[1 + i] >> 7);
\r
150 vic = buf[1 + i] & 0x7f;
\r
151 for(j = 0; j < ARRAY_SIZE(double_aspect_vic); j++)
\r
153 if(vic == double_aspect_vic[j])
\r
161 mode = hdmi_vic_to_videomode(vic);
\r
164 hdmi_add_videomode(mode, &pedid->modelist);
\r
171 // Parse CEA Short Audio Descriptor
\r
172 static int hdmi_edid_parse_cea_sad(unsigned char *buf, struct hdmi_edid *pedid)
\r
176 count = buf[0] & 0x1F;
\r
177 pedid->audio = kmalloc((count/3)*sizeof(struct hdmi_audio), GFP_KERNEL);
\r
178 if(pedid->audio == NULL)
\r
179 return E_HDMI_EDID_NOMEMORY;
\r
180 pedid->audio_num = count/3;
\r
181 for(i = 0; i < pedid->audio_num; i++)
\r
183 pedid->audio[i].type = (buf[1 + i*3] >> 3) & 0x0F;
\r
184 pedid->audio[i].channel = (buf[1 + i*3] & 0x07) + 1;
\r
185 pedid->audio[i].rate = buf[1 + i*3 + 1];
\r
186 if(pedid->audio[i].type == HDMI_AUDIO_LPCM)//LPCM
\r
188 pedid->audio[i].word_length = buf[1 + i*3 + 2];
\r
190 // printk("[EDID-CEA] type %d channel %d rate %d word length %d\n",
\r
191 // pedid->audio[i].type, pedid->audio[i].channel, pedid->audio[i].rate, pedid->audio[i].word_length);
\r
193 return E_HDMI_EDID_SUCCESS;
\r
195 // Parse CEA 861 Serial Extension.
\r
196 static int hdmi_edid_parse_extensions_cea(unsigned char *buf, struct hdmi_edid *pedid)
\r
198 unsigned int ddc_offset, native_dtd_num, cur_offset = 4;
\r
199 unsigned int underscan_support, baseaudio_support;
\r
200 unsigned int tag, IEEEOUI = 0;
\r
201 // unsigned int supports_ai, dc_48bit, dc_36bit, dc_30bit, dc_y444;
\r
202 // unsigned char vic;
\r
205 return E_HDMI_EDID_PARAM;
\r
207 // Check ces extension version
\r
210 hdmi_edid_error("[EDID-CEA] error version.\n");
\r
211 return E_HDMI_EDID_VERSION;
\r
214 ddc_offset = buf[2];
\r
215 underscan_support = (buf[3] >> 7) & 0x01;
\r
216 baseaudio_support = (buf[3] >> 6) & 0x01;
\r
217 pedid->ycbcr444 = (buf[3] >> 5) & 0x01;
\r
218 pedid->ycbcr422 = (buf[3] >> 4) & 0x01;
\r
219 native_dtd_num = buf[3] & 0x0F;
\r
220 pedid->base_audio_support = baseaudio_support;
\r
222 // Parse data block
\r
223 while(cur_offset < ddc_offset)
\r
225 tag = buf[cur_offset] >> 5;
\r
228 case 0x02: // Video Data Block
\r
229 hdmi_edid_debug("[EDID-CEA] It is a Video Data Block.\n");
\r
230 hdmi_edid_get_cea_svd(buf + cur_offset, pedid);
\r
232 case 0x01: // Audio Data Block
\r
233 hdmi_edid_debug("[EDID-CEA] It is a Audio Data Block.\n");
\r
234 hdmi_edid_parse_cea_sad(buf + cur_offset, pedid);
\r
236 case 0x04: // Speaker Allocation Data Block
\r
237 hdmi_edid_debug("[EDID-CEA] It is a Speaker Allocatio Data Block.\n");
\r
239 case 0x03: // Vendor Specific Data Block
\r
240 hdmi_edid_debug("[EDID-CEA] It is a Vendor Specific Data Block.\n");
\r
242 IEEEOUI = buf[cur_offset + 2 + 1];
\r
244 IEEEOUI += buf[cur_offset + 1 + 1];
\r
246 IEEEOUI += buf[cur_offset + 1];
\r
247 hdmi_edid_debug("[EDID-CEA] IEEEOUI is 0x%08x.\n", IEEEOUI);
\r
248 if(IEEEOUI == 0x0c03)
\r
249 pedid->sink_hdmi = 1;
\r
252 // pedid->deepcolor = (buf[cur_offset + 5] >> 3) & 0x0F;
\r
253 // supports_ai = buf[cur_offset + 5] >> 7;
\r
254 // dc_48bit = (buf[cur_offset + 5] >> 6) & 0x1;
\r
255 // dc_36bit = (buf[cur_offset + 5] >> 5) & 0x1;
\r
256 // dc_30bit = (buf[cur_offset + 5] >> 4) & 0x1;
\r
257 // dc_y444 = (buf[cur_offset + 5] >> 3) & 0x1;
\r
258 // hdmi_edid_debug("[EDID-CEA] supports_ai %d dc_48bit %d dc_36bit %d dc_30bit %d dc_y444 %d \n", supports_ai, dc_48bit, dc_36bit, dc_30bit, dc_y444);
\r
261 // pedid->maxtmdsclock = buf[cur_offset + 6] * 5000000;
\r
264 // pedid->latency_fields_present = (buf[cur_offset + 7] & 0x80) ? 1:0;
\r
265 // pedid->i_latency_fields_present = (buf[cur_offset + 7] & 0x40) ? 1:0;
\r
267 // if(count > 9 && pedid->latency_fields_present)
\r
269 // pedid->video_latency = buf[cur_offset + 8];
\r
270 // pedid->audio_latency = buf[cur_offset + 9];
\r
272 // if(count > 11 && pedid->i_latency_fields_present)
\r
274 // pedid->interlaced_video_latency = buf[cur_offset + 10];
\r
275 // pedid->interlaced_audio_latency = buf[cur_offset + 11];
\r
278 case 0x05: // VESA DTC Data Block
\r
279 hdmi_edid_debug("[EDID-CEA] It is a VESA DTC Data Block.\n");
\r
281 case 0x07: // Use Extended Tag
\r
282 hdmi_edid_debug("[EDID-CEA] It is a Use Extended Tag Data Block.\n");
\r
285 hdmi_edid_error("[EDID-CEA] unkowned data block tag.\n");
\r
288 cur_offset += (buf[cur_offset] & 0x1F) + 1;
\r
293 struct fb_videomode *vmode = kmalloc(sizeof(struct fb_videomode), GFP_KERNEL);
\r
295 return E_HDMI_EDID_SUCCESS;
\r
296 while(ddc_offset < HDMI_EDID_BLOCK_SIZE - 2) //buf[126] = 0 and buf[127] = checksum
\r
298 if(!buf[ddc_offset] && !buf[ddc_offset + 1])
\r
300 memset(vmode, 0, sizeof(struct fb_videomode));
\r
301 hdmi_edid_parse_dtd(buf + ddc_offset, vmode);
\r
302 hdmi_add_videomode(vmode, &pedid->modelist);
\r
308 return E_HDMI_EDID_SUCCESS;
\r
311 static int hdmi_edid_parse_extensions(unsigned char *buf, struct hdmi_edid *pedid)
\r
315 if(buf == NULL || pedid == NULL)
\r
316 return E_HDMI_EDID_PARAM;
\r
319 rc = hdmi_edid_checksum(buf);
\r
320 if( rc != E_HDMI_EDID_SUCCESS)
\r
322 hdmi_edid_error("[EDID] extensions block checksum error\n");
\r
323 return E_HDMI_EDID_CHECKSUM;
\r
329 hdmi_edid_debug("[EDID-EXTEND] It is a extensions block map.\n");
\r
332 hdmi_edid_debug("[EDID-EXTEND] It is a CEA 861 Series Extension.\n");
\r
333 hdmi_edid_parse_extensions_cea(buf, pedid);
\r
336 hdmi_edid_debug("[EDID-EXTEND] It is a Video Timing Block Extension.\n");
\r
339 hdmi_edid_debug("[EDID-EXTEND] It is a Display Information Extension.\n");
\r
342 hdmi_edid_debug("[EDID-EXTEND] It is a Localized String Extension.\n");
\r
345 hdmi_edid_debug("[EDID-EXTEND] It is a Digital Packet Video Link Extension.\n");
\r
348 hdmi_edid_error("[EDID-EXTEND] Unkowned extension.\n");
\r
349 return E_HDMI_EDID_UNKOWNDATA;
\r
352 return E_HDMI_EDID_SUCCESS;
\r
356 int hdmi_sys_parse_edid(struct hdmi* hdmi)
\r
358 struct hdmi_edid *pedid;
\r
359 unsigned char *buff = NULL;
\r
360 int rc = HDMI_ERROR_SUCESS, extendblock = 0, i;
\r
363 return HDMI_ERROR_FALSE;
\r
365 pedid = &(hdmi->edid);
\r
366 memset(pedid, 0, sizeof(struct hdmi_edid));
\r
367 INIT_LIST_HEAD(&pedid->modelist);
\r
369 buff = kmalloc(HDMI_EDID_BLOCK_SIZE, GFP_KERNEL);
\r
372 hdmi_dbg(hdmi->dev, "[%s] can not allocate memory for edid buff.\n", __FUNCTION__);
\r
375 // Read base block edid.
\r
376 memset(buff, 0 , HDMI_EDID_BLOCK_SIZE);
\r
377 rc = hdmi->read_edid(0, buff);
\r
380 dev_err(hdmi->dev, "[HDMI] read edid base block error\n");
\r
383 rc = hdmi_edid_parse_base(buff, &extendblock, pedid);
\r
386 dev_err(hdmi->dev, "[HDMI] parse edid base block error\n");
\r
389 for(i = 1; i < extendblock + 1; i++)
\r
391 memset(buff, 0 , HDMI_EDID_BLOCK_SIZE);
\r
392 rc = hdmi->read_edid(i, buff);
\r
395 printk("[HDMI] read edid block %d error\n", i);
\r
398 rc = hdmi_edid_parse_extensions(buff, pedid);
\r
401 dev_err(hdmi->dev, "[HDMI] parse edid block %d error\n", i);
\r
408 rc = hdmi_ouputmode_select(hdmi, rc);
\r