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 // hdmi_edid_debug("[EDID-CEA] ddc_offset %d underscan_support %d baseaudio_support %d yuv_support %d native_dtd_num %d\n", ddc_offset, underscan_support, baseaudio_support, yuv_support, native_dtd_num);
\r
221 // Parse data block
\r
222 while(cur_offset < ddc_offset)
\r
224 tag = buf[cur_offset] >> 5;
\r
227 case 0x02: // Video Data Block
\r
228 hdmi_edid_debug("[EDID-CEA] It is a Video Data Block.\n");
\r
229 hdmi_edid_get_cea_svd(buf + cur_offset, pedid);
\r
231 case 0x01: // Audio Data Block
\r
232 hdmi_edid_debug("[EDID-CEA] It is a Audio Data Block.\n");
\r
233 hdmi_edid_parse_cea_sad(buf + cur_offset, pedid);
\r
235 case 0x04: // Speaker Allocation Data Block
\r
236 hdmi_edid_debug("[EDID-CEA] It is a Speaker Allocatio Data Block.\n");
\r
238 case 0x03: // Vendor Specific Data Block
\r
239 hdmi_edid_debug("[EDID-CEA] It is a Vendor Specific Data Block.\n");
\r
241 IEEEOUI = buf[cur_offset + 2 + 1];
\r
243 IEEEOUI += buf[cur_offset + 1 + 1];
\r
245 IEEEOUI += buf[cur_offset + 1];
\r
246 hdmi_edid_debug("[EDID-CEA] IEEEOUI is 0x%08x.\n", IEEEOUI);
\r
247 if(IEEEOUI == 0x0c03)
\r
248 pedid->sink_hdmi = 1;
\r
251 // pedid->deepcolor = (buf[cur_offset + 5] >> 3) & 0x0F;
\r
252 // supports_ai = buf[cur_offset + 5] >> 7;
\r
253 // dc_48bit = (buf[cur_offset + 5] >> 6) & 0x1;
\r
254 // dc_36bit = (buf[cur_offset + 5] >> 5) & 0x1;
\r
255 // dc_30bit = (buf[cur_offset + 5] >> 4) & 0x1;
\r
256 // dc_y444 = (buf[cur_offset + 5] >> 3) & 0x1;
\r
257 // 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
260 // pedid->maxtmdsclock = buf[cur_offset + 6] * 5000000;
\r
263 // pedid->latency_fields_present = (buf[cur_offset + 7] & 0x80) ? 1:0;
\r
264 // pedid->i_latency_fields_present = (buf[cur_offset + 7] & 0x40) ? 1:0;
\r
266 // if(count > 9 && pedid->latency_fields_present)
\r
268 // pedid->video_latency = buf[cur_offset + 8];
\r
269 // pedid->audio_latency = buf[cur_offset + 9];
\r
271 // if(count > 11 && pedid->i_latency_fields_present)
\r
273 // pedid->interlaced_video_latency = buf[cur_offset + 10];
\r
274 // pedid->interlaced_audio_latency = buf[cur_offset + 11];
\r
277 case 0x05: // VESA DTC Data Block
\r
278 hdmi_edid_debug("[EDID-CEA] It is a VESA DTC Data Block.\n");
\r
280 case 0x07: // Use Extended Tag
\r
281 hdmi_edid_debug("[EDID-CEA] It is a Use Extended Tag Data Block.\n");
\r
284 hdmi_edid_error("[EDID-CEA] unkowned data block tag.\n");
\r
287 cur_offset += (buf[cur_offset] & 0x1F) + 1;
\r
292 struct fb_videomode *vmode = kmalloc(sizeof(struct fb_videomode), GFP_KERNEL);
\r
294 return E_HDMI_EDID_SUCCESS;
\r
295 while(ddc_offset < HDMI_EDID_BLOCK_SIZE - 2) //buf[126] = 0 and buf[127] = checksum
\r
297 if(!buf[ddc_offset] && !buf[ddc_offset + 1])
\r
299 memset(vmode, 0, sizeof(struct fb_videomode));
\r
300 hdmi_edid_parse_dtd(buf + ddc_offset, vmode);
\r
301 hdmi_add_videomode(vmode, &pedid->modelist);
\r
307 return E_HDMI_EDID_SUCCESS;
\r
310 static int hdmi_edid_parse_extensions(unsigned char *buf, struct hdmi_edid *pedid)
\r
314 if(buf == NULL || pedid == NULL)
\r
315 return E_HDMI_EDID_PARAM;
\r
318 rc = hdmi_edid_checksum(buf);
\r
319 if( rc != E_HDMI_EDID_SUCCESS)
\r
321 hdmi_edid_error("[EDID] extensions block checksum error\n");
\r
322 return E_HDMI_EDID_CHECKSUM;
\r
328 hdmi_edid_debug("[EDID-EXTEND] It is a extensions block map.\n");
\r
331 hdmi_edid_debug("[EDID-EXTEND] It is a CEA 861 Series Extension.\n");
\r
332 hdmi_edid_parse_extensions_cea(buf, pedid);
\r
335 hdmi_edid_debug("[EDID-EXTEND] It is a Video Timing Block Extension.\n");
\r
338 hdmi_edid_debug("[EDID-EXTEND] It is a Display Information Extension.\n");
\r
341 hdmi_edid_debug("[EDID-EXTEND] It is a Localized String Extension.\n");
\r
344 hdmi_edid_debug("[EDID-EXTEND] It is a Digital Packet Video Link Extension.\n");
\r
347 hdmi_edid_error("[EDID-EXTEND] Unkowned extension.\n");
\r
348 return E_HDMI_EDID_UNKOWNDATA;
\r
351 return E_HDMI_EDID_SUCCESS;
\r
355 int hdmi_sys_parse_edid(struct hdmi* hdmi)
\r
357 struct hdmi_edid *pedid;
\r
358 unsigned char *buff = NULL;
\r
359 int rc = HDMI_ERROR_SUCESS, extendblock = 0, i;
\r
362 return HDMI_ERROR_FALSE;
\r
364 pedid = &(hdmi->edid);
\r
365 memset(pedid, 0, sizeof(struct hdmi_edid));
\r
366 INIT_LIST_HEAD(&pedid->modelist);
\r
368 buff = kmalloc(HDMI_EDID_BLOCK_SIZE, GFP_KERNEL);
\r
371 hdmi_dbg(hdmi->dev, "[%s] can not allocate memory for edid buff.\n", __FUNCTION__);
\r
374 // Read base block edid.
\r
375 memset(buff, 0 , HDMI_EDID_BLOCK_SIZE);
\r
376 rc = hdmi->read_edid(0, buff);
\r
379 dev_err(hdmi->dev, "[HDMI] read edid base block error\n");
\r
382 rc = hdmi_edid_parse_base(buff, &extendblock, pedid);
\r
385 dev_err(hdmi->dev, "[HDMI] parse edid base block error\n");
\r
388 for(i = 1; i < extendblock + 1; i++)
\r
390 memset(buff, 0 , HDMI_EDID_BLOCK_SIZE);
\r
391 rc = hdmi->read_edid(i, buff);
\r
394 printk("[HDMI] read edid block %d error\n", i);
\r
397 rc = hdmi_edid_parse_extensions(buff, pedid);
\r
400 dev_err(hdmi->dev, "[HDMI] parse edid block %d error\n", i);
\r
407 rc = hdmi_ouputmode_select(hdmi, rc);
\r