ac8c3984c47df72c74dc5550f0c103d5c09423f6
[firefly-linux-kernel-4.4.55.git] / drivers / video / hdmi / chips / rk610 / rk610_hdmi_hw.c
1 #include <linux/delay.h>\r
2 #include <linux/mfd/rk610_core.h>\r
3 #include "rk610_hdmi.h"\r
4 #include "rk610_hdmi_hw.h"\r
5 static struct rk610_hdmi_hw_inf g_hw_inf;\r
6 static EDID_INF g_edid;\r
7 static byte edid_buf[EDID_BLOCK_SIZE];\r
8 static struct edid_result Rk610_edid_result;\r
9 byte DoEdidRead (struct i2c_client *client);\r
10 static int RK610_hdmi_soft_reset(struct i2c_client *client);\r
11 static int Rk610_hdmi_Display_switch(struct i2c_client *client);\r
12 static void Rk610_hdmi_plug(struct i2c_client *client);\r
13 static void Rk610_hdmi_unplug(struct i2c_client *client);\r
14 \r
15 static int Rk610_hdmi_i2c_read_p0_reg(struct i2c_client *client, char reg, char *val)\r
16 {\r
17         return i2c_master_reg8_recv(client, reg, val, 1, 100*1000) > 0? 0: -EINVAL;\r
18 }\r
19 static int Rk610_hdmi_i2c_write_p0_reg(struct i2c_client *client, char reg, char *val)\r
20 {\r
21         return i2c_master_reg8_send(client, reg, val, 1, 100*1000) > 0? 0: -EINVAL;\r
22 }\r
23 \r
24 static int Rk610_hdmi_pwr_mode(struct i2c_client *client, int mode)\r
25 {\r
26     char c;\r
27     int ret=0;\r
28     switch(mode){\r
29      case NORMAL:\r
30         c=0x00;\r
31             ret =Rk610_hdmi_i2c_write_p0_reg(client, 0xe4, &c);\r
32             c=0x00;\r
33             ret =Rk610_hdmi_i2c_write_p0_reg(client, 0xe7, &c);\r
34         c=0x8e;\r
35             ret =Rk610_hdmi_i2c_write_p0_reg(client, 0xe1, &c);\r
36             c=0x00;\r
37             ret =Rk610_hdmi_i2c_write_p0_reg(client, 0xe5, &c);\r
38                 c=0x82;\r
39             ret =Rk610_hdmi_i2c_write_p0_reg(client, 0xe3, &c);   \r
40             break;\r
41         case LOWER_PWR:\r
42                 c=0x02;\r
43             ret =Rk610_hdmi_i2c_write_p0_reg(client, 0xe3, &c);\r
44             c=0x1c;\r
45             ret =Rk610_hdmi_i2c_write_p0_reg(client, 0xe5, &c);\r
46             c=0x8c;\r
47             ret =Rk610_hdmi_i2c_write_p0_reg(client, 0xe1, &c);\r
48         c=0x04;\r
49             ret =Rk610_hdmi_i2c_write_p0_reg(client, 0xe7, &c);\r
50             c=0x03;\r
51             ret =Rk610_hdmi_i2c_write_p0_reg(client, 0xe4, &c);\r
52             break;\r
53         default:\r
54             RK610_ERR(&client->dev,"unkown rk610 hdmi pwr mode %d\n",mode);\r
55     }\r
56     return ret;\r
57 }\r
58 \r
59 #ifdef CONFIG_HAS_EARLYSUSPEND\r
60 int Rk610_hdmi_suspend(struct i2c_client *client)\r
61 {\r
62     int ret = 0;\r
63         RK610_DBG(&client->dev,"%s \n",__FUNCTION__);\r
64         g_hw_inf.suspend_flag = 1;\r
65         g_hw_inf.hpd = 0;\r
66         Rk610_hdmi_unplug(client);\r
67         return ret;\r
68 }\r
69 int Rk610_hdmi_resume(struct i2c_client *client)\r
70 {\r
71         int ret = 0;\r
72         char c = 0;\r
73         RK610_DBG(&client->dev, "%s \n",__FUNCTION__);\r
74         Rk610_hdmi_i2c_read_p0_reg(client, 0xc8, &c);\r
75         if(c & RK610_HPD_PLUG ){\r
76         Rk610_hdmi_plug(client);\r
77                 g_hw_inf.hpd=1;\r
78         }\r
79         else{\r
80         Rk610_hdmi_unplug(client);\r
81                 g_hw_inf.hpd=0;\r
82         }\r
83         g_hw_inf.suspend_flag = 0;\r
84         return ret;\r
85 }\r
86 #endif\r
87 static int Rk610_hdmi_sys_power_down(struct i2c_client *client)\r
88 {\r
89     char c = 0;\r
90     int ret = 0;\r
91     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);\r
92     c= RK610_SYS_CLK<<2 |RK610_SYS_PWR_OFF<<1 |RK610_INT_POL;\r
93         ret =Rk610_hdmi_i2c_write_p0_reg(client, 0x00, &c);\r
94         return ret;\r
95 }\r
96 static int Rk610_hdmi_sys_power_up(struct i2c_client *client)\r
97 {\r
98     char c = 0;\r
99     int ret = 0;\r
100     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);\r
101     c= RK610_SYS_CLK<<2 |RK610_SYS_PWR_ON<<1 |RK610_INT_POL;\r
102         ret =Rk610_hdmi_i2c_write_p0_reg(client, 0x00, &c);\r
103         return ret;\r
104 }\r
105 //X=11.2896M/(4*100k), X = {0x4c,0x4b}\r
106 static int RK610_DDC_BUS_CONFIG(struct i2c_client *client)\r
107 {\r
108     char c = 0;\r
109     int ret = 0;\r
110     c= RK610_DDC_CONFIG&0xff;\r
111         ret =Rk610_hdmi_i2c_write_p0_reg(client, 0x4b, &c);\r
112         c= (RK610_DDC_CONFIG>>8)&0xff;\r
113         ret =Rk610_hdmi_i2c_write_p0_reg(client, 0x4c, &c);\r
114         return ret;\r
115 }\r
116 static int RK610_read_edid_block(struct i2c_client *client,u8 block, u8 * buf)\r
117 {\r
118     char c = 0;\r
119     int ret = 0,i;\r
120     u8 Segment = 0;\r
121         u8 Offset = 0;\r
122     if(block%2)\r
123     Offset = EDID_BLOCK_SIZE;\r
124     if(block/2)\r
125     Segment = 1;\r
126     RK610_DBG(&client->dev,"EDID DATA (Segment = %d Block = %d Offset = %d):\n", (int) Segment, (int) block, (int) Offset);\r
127     //set edid fifo first addr\r
128         c = 0x00;\r
129         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0x4f, &c);\r
130         //set edid word address 00/80\r
131         c = Offset;\r
132         ret =Rk610_hdmi_i2c_write_p0_reg(client, 0x4e, &c);\r
133         //set edid segment pointer\r
134         c = Segment;\r
135         ret =Rk610_hdmi_i2c_write_p0_reg(client, 0x4d, &c);\r
136         \r
137         //enable edid interrupt\r
138         c=0xc6;\r
139         ret =Rk610_hdmi_i2c_write_p0_reg(client, 0xc0, &c);\r
140         //wait edid interrupt\r
141     msleep(10);\r
142         RK610_DBG(&client->dev,"Interrupt generated\n");\r
143         c=0x00;\r
144         ret =Rk610_hdmi_i2c_read_p0_reg(client, 0xc1, &c);\r
145         RK610_DBG(&client->dev,"Interrupt reg=%x \n",c);\r
146         //clear EDID interrupt reg\r
147         c=0x04;\r
148         ret =Rk610_hdmi_i2c_write_p0_reg(client, 0xc1, &c);\r
149         for(i=0; i <EDID_BLOCK_SIZE;i++){\r
150             c = 0;          \r
151                 Rk610_hdmi_i2c_read_p0_reg(client, 0x50, &c);\r
152                 buf[i] = c;\r
153         }\r
154         return ret;\r
155 }\r
156 #if 0\r
157 //------------------------------------------------------------------------------\r
158 // Function Name: Parse861ShortDescriptors()\r
159 // Function Description: Parse CEA-861 extension short descriptors of the EDID block\r
160 //                  passed as a parameter and save them in global structure g_edid.\r
161 //\r
162 // Accepts: A pointer to the EDID 861 Extension block being parsed.\r
163 // Returns: EDID_PARSED_OK if EDID parsed correctly. Error code if failed.\r
164 // Globals: EDID data\r
165 // NOTE: Fields that are not supported by the 9022/4 (such as deep color) were not parsed.\r
166 //------------------------------------------------------------------------------\r
167 byte Parse861ShortDescriptors (byte *Data)\r
168 {\r
169     byte LongDescriptorOffset;\r
170     byte DataBlockLength;\r
171     byte DataIndex;\r
172     byte ExtendedTagCode;\r
173     byte VSDB_BaseOffset = 0;\r
174 \r
175     byte V_DescriptorIndex = 0;  // static to support more than one extension\r
176     byte A_DescriptorIndex = 0;  // static to support more than one extension\r
177 \r
178     byte TagCode;\r
179 \r
180     byte i;\r
181     byte j;\r
182 \r
183     if (Data[EDID_TAG_ADDR] != EDID_EXTENSION_TAG)\r
184     {\r
185         RK610_HDMI_ERR("EDID -> Extension Tag Error\n");\r
186         return EDID_EXT_TAG_ERROR;\r
187     }\r
188 \r
189     if (Data[EDID_REV_ADDR] != EDID_REV_THREE)\r
190     {\r
191         RK610_HDMI_ERR("EDID -> Revision Error\n"));\r
192         return EDID_REV_ADDR_ERROR;\r
193     }\r
194 \r
195     LongDescriptorOffset = Data[LONG_DESCR_PTR_IDX];    // block offset where long descriptors start\r
196 \r
197     g_edid.UnderScan = ((Data[MISC_SUPPORT_IDX]) >> 7) & LSBIT;  // byte #3 of CEA extension version 3\r
198     g_edid.BasicAudio = ((Data[MISC_SUPPORT_IDX]) >> 6) & LSBIT;\r
199     g_edid.YCbCr_4_4_4 = ((Data[MISC_SUPPORT_IDX]) >> 5) & LSBIT;\r
200     g_edid.YCbCr_4_2_2 = ((Data[MISC_SUPPORT_IDX]) >> 4) & LSBIT;\r
201 \r
202     DataIndex = EDID_DATA_START;            // 4\r
203 \r
204     while (DataIndex < LongDescriptorOffset)\r
205     {\r
206         TagCode = (Data[DataIndex] >> 5) & THREE_LSBITS;\r
207         DataBlockLength = Data[DataIndex++] & FIVE_LSBITS;\r
208         if ((DataIndex + DataBlockLength) > LongDescriptorOffset)\r
209         {\r
210             RK610_HDMI_ERR("EDID -> V Descriptor Overflow\n");\r
211             return EDID_V_DESCR_OVERFLOW;\r
212         }\r
213 \r
214         i = 0;                                  // num of short video descriptors in current data block\r
215 \r
216         switch (TagCode)\r
217         {\r
218             case VIDEO_D_BLOCK:\r
219                 while ((i < DataBlockLength) && (i < MAX_V_DESCRIPTORS))        // each SVD is 1 byte long\r
220                 {\r
221                     g_edid.VideoDescriptor[V_DescriptorIndex++] = Data[DataIndex++];\r
222                     i++;\r
223                 }\r
224                 DataIndex += DataBlockLength - i;   // if there are more STDs than MAX_V_DESCRIPTORS, skip the last ones. Update DataIndex\r
225 \r
226                 RK610_RK610_DBG(&client->dev,"EDID -> Short Descriptor Video Block\n");\r
227                 break;\r
228 \r
229             case AUDIO_D_BLOCK:\r
230                 while (i < DataBlockLength/3)       // each SAD is 3 bytes long\r
231                 {\r
232                     j = 0;\r
233                     while (j < AUDIO_DESCR_SIZE)    // 3\r
234                     {\r
235                         g_edid.AudioDescriptor[A_DescriptorIndex][j++] = Data[DataIndex++];\r
236                     }\r
237                     A_DescriptorIndex++;\r
238                     i++;\r
239                 }\r
240                 RK610_HDMI_DBG("EDID -> Short Descriptor Audio Block\n");\r
241                 break;\r
242 \r
243             case  SPKR_ALLOC_D_BLOCK:\r
244                 g_edid.SpkrAlloc[i++] = Data[DataIndex++];       // although 3 bytes are assigned to Speaker Allocation, only\r
245                 DataIndex += 2;                                     // the first one carries information, so the next two are ignored by this code.\r
246                 RK610_HDMI_DBG("EDID -> Short Descriptor Speaker Allocation Block\n");\r
247                 break;\r
248 \r
249             case USE_EXTENDED_TAG:\r
250                 ExtendedTagCode = Data[DataIndex++];\r
251 \r
252                 switch (ExtendedTagCode)\r
253                 {\r
254                     case VIDEO_CAPABILITY_D_BLOCK:\r
255                         RK610_HDMI_DBG("EDID -> Short Descriptor Video Capability Block\n");\r
256 \r
257                         // TO BE ADDED HERE: Save "video capability" parameters in g_edid data structure\r
258                         // Need to modify that structure definition\r
259                         // In the meantime: just increment DataIndex by 1\r
260                         DataIndex += 1;    // replace with reading and saving the proper data per CEA-861 sec. 7.5.6 while incrementing DataIndex\r
261                         break;\r
262 \r
263                     case COLORIMETRY_D_BLOCK:\r
264                         g_edid.ColorimetrySupportFlags = Data[DataIndex++] & BITS_1_0;\r
265                         g_edid.MetadataProfile = Data[DataIndex++] & BITS_2_1_0;\r
266 \r
267                         RK610_HDMI_DBG("EDID -> Short Descriptor Colorimetry Block\n");\r
268                         break;\r
269                 }\r
270                 break;\r
271 \r
272             case VENDOR_SPEC_D_BLOCK:\r
273                 VSDB_BaseOffset = DataIndex - 1;\r
274 \r
275                 if ((Data[DataIndex++] == 0x03) &&    // check if sink is HDMI compatible\r
276                     (Data[DataIndex++] == 0x0C) &&\r
277                     (Data[DataIndex++] == 0x00))\r
278 \r
279                     g_edid.RK610_HDMI_Sink = TRUE;\r
280                 else\r
281                     g_edid.RK610_HDMI_Sink = FALSE;\r
282 \r
283                 g_edid.CEC_A_B = Data[DataIndex++];  // CEC Physical address\r
284                 g_edid.CEC_C_D = Data[DataIndex++];\r
285 \r
286 #ifdef DEV_SUPPORT_CEC\r
287                                 // Take the Address that was passed in the EDID and use this API\r
288                                 // to set the physical address for CEC.\r
289                                 {\r
290                                         word    phyAddr;\r
291                                         phyAddr = (word)g_edid.CEC_C_D;  // Low-order nibbles\r
292                                         phyAddr |= ((word)g_edid.CEC_A_B << 8); // Hi-order nibbles\r
293                                         // Is the new PA different from the current PA?\r
294                                         if (phyAddr != SI_CecGetDevicePA ())\r
295                                         {\r
296                                                 // Yes!  So change the PA\r
297                                                 SI_CecSetDevicePA (phyAddr);\r
298                                         }\r
299                                 }\r
300 #endif\r
301 \r
302                 if ((DataIndex + 7) > VSDB_BaseOffset + DataBlockLength)        // Offset of 3D_Present bit in VSDB\r
303                         g_edid._3D_Supported = FALSE;\r
304                 else if (Data[DataIndex + 7] >> 7)\r
305                         g_edid._3D_Supported = TRUE;\r
306                 else\r
307                         g_edid._3D_Supported = FALSE;\r
308 \r
309                 DataIndex += DataBlockLength - RK610_HDMI_SIGNATURE_LEN - CEC_PHYS_ADDR_LEN; // Point to start of next block\r
310                 RK610_HDMI_DBG("EDID -> Short Descriptor Vendor Block\n");\r
311                 break;\r
312 \r
313             default:\r
314                 RK610_HDMI_DBG("EDID -> Unknown Tag Code\n");\r
315                 return EDID_UNKNOWN_TAG_CODE;\r
316 \r
317         }                   // End, Switch statement\r
318     }                       // End, while (DataIndex < LongDescriptorOffset) statement\r
319 \r
320     return EDID_SHORT_DESCRIPTORS_OK;\r
321 }\r
322 \r
323 //------------------------------------------------------------------------------\r
324 // Function Name: Parse861LongDescriptors()\r
325 // Function Description: Parse CEA-861 extension long descriptors of the EDID block\r
326 //                  passed as a parameter and printf() them to the screen.\r
327 //\r
328 // Accepts: A pointer to the EDID block being parsed\r
329 // Returns: An error code if no long descriptors found; EDID_PARSED_OK if descriptors found.\r
330 // Globals: none\r
331 //------------------------------------------------------------------------------\r
332 byte Parse861LongDescriptors (byte *Data)\r
333 {\r
334     byte LongDescriptorsOffset;\r
335     byte DescriptorNum = 1;\r
336 \r
337     LongDescriptorsOffset = Data[LONG_DESCR_PTR_IDX];   // EDID block offset 2 holds the offset\r
338 \r
339     if (!LongDescriptorsOffset)                         // per CEA-861-D, table 27\r
340     {\r
341         TPI_DEBUG_PRINT(("EDID -> No Detailed Descriptors\n"));\r
342         return EDID_NO_DETAILED_DESCRIPTORS;\r
343     }\r
344 \r
345     // of the 1st 18-byte descriptor\r
346     while (LongDescriptorsOffset + LONG_DESCR_LEN < EDID_BLOCK_SIZE)\r
347     {\r
348         TPI_EDID_PRINT(("Parse Results - CEA-861 Long Descriptor #%d:\n", (int) DescriptorNum));\r
349         TPI_EDID_PRINT(("===============================================================\n"));\r
350 \r
351 #if (CONF__TPI_EDID_PRINT == ENABLE)\r
352         if (!ParseDetailedTiming(Data, LongDescriptorsOffset, EDID_BLOCK_2_3))\r
353                         break;\r
354 #endif\r
355         LongDescriptorsOffset +=  LONG_DESCR_LEN;\r
356         DescriptorNum++;\r
357     }\r
358 \r
359     return EDID_LONG_DESCRIPTORS_OK;\r
360 }\r
361 \r
362 //------------------------------------------------------------------------------\r
363 // Function Name: Parse861Extensions()\r
364 // Function Description: Parse CEA-861 extensions from EDID ROM (EDID blocks beyond\r
365 //                  block #0). Save short descriptors in global structure\r
366 //                  g_edid. printf() long descriptors to the screen.\r
367 //\r
368 // Accepts: The number of extensions in the EDID being parsed\r
369 // Returns: EDID_PARSED_OK if EDID parsed correctly. Error code if failed.\r
370 // Globals: EDID data\r
371 // NOTE: Fields that are not supported by the 9022/4 (such as deep color) were not parsed.\r
372 //------------------------------------------------------------------------------\r
373 byte Parse861Extensions (struct i2c_client *client,byte NumOfExtensions)\r
374 {\r
375         byte i,j,k;\r
376         \r
377         byte ErrCode;\r
378         \r
379 //      byte V_DescriptorIndex = 0;\r
380 //      byte A_DescriptorIndex = 0;\r
381         \r
382     byte Block = 0;\r
383         \r
384         g_edid.HDMI_Sink = FALSE;\r
385 \r
386         do\r
387         {\r
388             Block++;\r
389             HDMI_DBG("\n");\r
390             \r
391             for (j=0, i=0; j<128; j++)\r
392             {\r
393                 k = edid_buf[j];\r
394                 HDMI_DBG("%2.2X ", (int) k);\r
395                 i++;\r
396         \r
397                 if (i == 0x10)\r
398                 {\r
399                     HDMI_DBG("\n");\r
400                     i = 0;\r
401                 }\r
402             }\r
403             HDMI_DBG("\n");\r
404             RK610_read_edid_block(client,Block, edid_buf);\r
405             if ((NumOfExtensions > 1) && (Block == 1))\r
406             {\r
407                 continue;\r
408             }\r
409         \r
410             ErrCode = Parse861ShortDescriptors(edid_buf);\r
411             if (ErrCode != EDID_SHORT_DESCRIPTORS_OK)\r
412             {\r
413                 return ErrCode;\r
414             }\r
415         \r
416             ErrCode = Parse861LongDescriptors(edid_buf);\r
417             if (ErrCode != EDID_LONG_DESCRIPTORS_OK)\r
418             {\r
419                 return ErrCode;\r
420             }\r
421         \r
422         } while (Block < NumOfExtensions);\r
423 \r
424         return EDID_OK;\r
425 }\r
426 \r
427 //------------------------------------------------------------------------------\r
428 // Function Name: ParseEDID()\r
429 // Function Description: Extract sink properties from its EDID file and save them in\r
430 //                  global structure g_edid.\r
431 //\r
432 // Accepts: none\r
433 // Returns: TRUE or FLASE\r
434 // Globals: EDID data\r
435 // NOTE: Fields that are not supported by the 9022/4 (such as deep color) were not parsed.\r
436 //------------------------------------------------------------------------------\r
437 static byte ParseEDID (byte *pEdid, byte *numExt)\r
438 {\r
439         if (!CheckEDID_Header(pEdid))\r
440         {\r
441                 // first 8 bytes of EDID must be {0, FF, FF, FF, FF, FF, FF, 0}\r
442                 HDMI_ERR("EDID -> Incorrect Header\n");\r
443                 return EDID_INCORRECT_HEADER;\r
444         }\r
445 \r
446         if (!DoEDID_Checksum(pEdid))\r
447         {\r
448                 // non-zero EDID checksum\r
449                 HDMI_ERR("EDID -> Checksum Error\n");\r
450                 return EDID_CHECKSUM_ERROR;\r
451         }\r
452 \r
453         *numExt = pEdid[NUM_OF_EXTEN_ADDR];     // read # of extensions from offset 0x7E of block 0\r
454         HDMI_DBG("EDID -> 861 Extensions = %d\n", (int) *numExt);\r
455 \r
456         if (!(*numExt))\r
457         {\r
458                 // No extensions to worry about\r
459                 HDMI_DBG("EDID -> EDID_NO_861_EXTENSIONS\n");\r
460                 return EDID_NO_861_EXTENSIONS;\r
461         }\r
462         return EDID_OK;\r
463 }\r
464 #endif\r
465 \r
466 //------------------------------------------------------------------------------\r
467 // Function Name: CheckEDID_Header()\r
468 // Function Description: Checks if EDID header is correct per VESA E-EDID standard\r
469 //\r
470 // Accepts: Pointer to 1st EDID block\r
471 // Returns: TRUE or FLASE\r
472 // Globals: EDID data\r
473 //------------------------------------------------------------------------------\r
474 byte CheckEDID_Header (byte *Block)\r
475 {\r
476         byte i = 0;\r
477 \r
478         if (Block[i])               // byte 0 must be 0\r
479         return FALSE;\r
480 \r
481         for (i = 1; i < 1 + EDID_HDR_NO_OF_FF; i++)\r
482         {\r
483         if(Block[i] != 0xFF)    // bytes [1..6] must be 0xFF\r
484                 return FALSE;\r
485         }\r
486 \r
487         if (Block[i])               // byte 7 must be 0\r
488         return FALSE;\r
489 \r
490         return TRUE;\r
491 }\r
492 \r
493 //------------------------------------------------------------------------------\r
494 // Function Name: DoEDID_Checksum()\r
495 // Function Description: Calculte checksum of the 128 byte block pointed to by the\r
496 //                  pointer passed as parameter\r
497 //\r
498 // Accepts: Pointer to a 128 byte block whose checksum needs to be calculated\r
499 // Returns: TRUE or FLASE\r
500 // Globals: EDID data\r
501 //------------------------------------------------------------------------------\r
502 byte DoEDID_Checksum (byte *Block)\r
503 {\r
504         byte i;\r
505         byte CheckSum = 0;\r
506 \r
507         for (i = 0; i < EDID_BLOCK_SIZE; i++)\r
508         CheckSum += Block[i];\r
509 \r
510         if (CheckSum)\r
511         return FALSE;\r
512 \r
513         return TRUE;\r
514 }\r
515 //------------------------------------------------------------------------------\r
516 // Function Name: Parse861ShortDescriptors()\r
517 // Function Description: Parse CEA-861 extension short descriptors of the EDID block\r
518 //                  passed as a parameter and save them in global structure g_edid.\r
519 //\r
520 // Accepts: A pointer to the EDID 861 Extension block being parsed.\r
521 // Returns: EDID_PARSED_OK if EDID parsed correctly. Error code if failed.\r
522 // Globals: EDID data\r
523 // NOTE: Fields that are not supported by the 9022/4 (such as deep color) were not parsed.\r
524 //------------------------------------------------------------------------------\r
525 byte Parse861ShortDescriptors (struct i2c_client *client,byte *Data)\r
526 {\r
527     byte LongDescriptorOffset;\r
528     byte DataBlockLength;\r
529     byte DataIndex;\r
530     byte ExtendedTagCode;\r
531     byte VSDB_BaseOffset = 0;\r
532 \r
533     byte V_DescriptorIndex = 0;  // static to support more than one extension\r
534     byte A_DescriptorIndex = 0;  // static to support more than one extension\r
535 \r
536     byte TagCode;\r
537 \r
538     byte i;\r
539     byte j;\r
540 \r
541     if (Data[EDID_TAG_ADDR] != EDID_EXTENSION_TAG)\r
542     {\r
543         RK610_ERR(&client->dev,"EDID -> Extension Tag Error\n");\r
544         return EDID_EXT_TAG_ERROR;\r
545     }\r
546 \r
547     if (Data[EDID_REV_ADDR] != EDID_REV_THREE)\r
548     {\r
549         RK610_ERR(&client->dev,"EDID -> Revision Error\n");\r
550         return EDID_REV_ADDR_ERROR;\r
551     }\r
552 \r
553     LongDescriptorOffset = Data[LONG_DESCR_PTR_IDX];    // block offset where long descriptors start\r
554 \r
555     g_edid.UnderScan = ((Data[MISC_SUPPORT_IDX]) >> 7) & LSBIT;  // byte #3 of CEA extension version 3\r
556     g_edid.BasicAudio = ((Data[MISC_SUPPORT_IDX]) >> 6) & LSBIT;\r
557     g_edid.YCbCr_4_4_4 = ((Data[MISC_SUPPORT_IDX]) >> 5) & LSBIT;\r
558     g_edid.YCbCr_4_2_2 = ((Data[MISC_SUPPORT_IDX]) >> 4) & LSBIT;\r
559 \r
560     DataIndex = EDID_DATA_START;            // 4\r
561 \r
562     while (DataIndex < LongDescriptorOffset)\r
563     {\r
564         TagCode = (Data[DataIndex] >> 5) & THREE_LSBITS;\r
565         DataBlockLength = Data[DataIndex++] & FIVE_LSBITS;\r
566         if ((DataIndex + DataBlockLength) > LongDescriptorOffset)\r
567         {\r
568             RK610_ERR(&client->dev,"EDID -> V Descriptor Overflow\n");\r
569             return EDID_V_DESCR_OVERFLOW;\r
570         }\r
571 \r
572         i = 0;                                  // num of short video descriptors in current data block\r
573 \r
574         switch (TagCode)\r
575         {\r
576             case VIDEO_D_BLOCK:\r
577                 while ((i < DataBlockLength) && (i < MAX_V_DESCRIPTORS))        // each SVD is 1 byte long\r
578                 {\r
579                     g_edid.VideoDescriptor[V_DescriptorIndex++] = Data[DataIndex++];\r
580                     i++;\r
581                 }\r
582                 DataIndex += DataBlockLength - i;   // if there are more STDs than MAX_V_DESCRIPTORS, skip the last ones. Update DataIndex\r
583 \r
584                 RK610_DBG(&client->dev,"EDID -> Short Descriptor Video Block\n");\r
585                 break;\r
586 \r
587             case AUDIO_D_BLOCK:\r
588                 while (i < DataBlockLength/3)       // each SAD is 3 bytes long\r
589                 {\r
590                     j = 0;\r
591                     while (j < AUDIO_DESCR_SIZE)    // 3\r
592                     {\r
593                         g_edid.AudioDescriptor[A_DescriptorIndex][j++] = Data[DataIndex++];\r
594                     }\r
595                     A_DescriptorIndex++;\r
596                     i++;\r
597                 }\r
598                 RK610_DBG(&client->dev,"EDID -> Short Descriptor Audio Block\n");\r
599                 break;\r
600 \r
601             case  SPKR_ALLOC_D_BLOCK:\r
602                 g_edid.SpkrAlloc[i++] = Data[DataIndex++];       // although 3 bytes are assigned to Speaker Allocation, only\r
603                 DataIndex += 2;                                     // the first one carries information, so the next two are ignored by this code.\r
604                 RK610_DBG(&client->dev,"EDID -> Short Descriptor Speaker Allocation Block\n");\r
605                 break;\r
606 \r
607             case USE_EXTENDED_TAG:\r
608                 ExtendedTagCode = Data[DataIndex++];\r
609 \r
610                 switch (ExtendedTagCode)\r
611                 {\r
612                     case VIDEO_CAPABILITY_D_BLOCK:\r
613                         RK610_DBG(&client->dev,"EDID -> Short Descriptor Video Capability Block\n");\r
614 \r
615                         // TO BE ADDED HERE: Save "video capability" parameters in g_edid data structure\r
616                         // Need to modify that structure definition\r
617                         // In the meantime: just increment DataIndex by 1\r
618                         DataIndex += 1;    // replace with reading and saving the proper data per CEA-861 sec. 7.5.6 while incrementing DataIndex\r
619                         break;\r
620 \r
621                     case COLORIMETRY_D_BLOCK:\r
622                         g_edid.ColorimetrySupportFlags = Data[DataIndex++] & BITS_1_0;\r
623                         g_edid.MetadataProfile = Data[DataIndex++] & BITS_2_1_0;\r
624 \r
625                         RK610_DBG(&client->dev,"EDID -> Short Descriptor Colorimetry Block\n");\r
626                         break;\r
627                 }\r
628                 break;\r
629 \r
630             case VENDOR_SPEC_D_BLOCK:\r
631                 VSDB_BaseOffset = DataIndex - 1;\r
632 \r
633                 if ((Data[DataIndex++] == 0x03) &&    // check if sink is HDMI compatible\r
634                     (Data[DataIndex++] == 0x0C) &&\r
635                     (Data[DataIndex++] == 0x00))\r
636 \r
637                     g_edid.HDMI_Sink = TRUE;\r
638                 else\r
639                     g_edid.HDMI_Sink = FALSE;\r
640 \r
641                 g_edid.CEC_A_B = Data[DataIndex++];  // CEC Physical address\r
642                 g_edid.CEC_C_D = Data[DataIndex++];\r
643 \r
644 #ifdef DEV_SUPPORT_CEC\r
645                                 // Take the Address that was passed in the EDID and use this API\r
646                                 // to set the physical address for CEC.\r
647                                 {\r
648                                         word    phyAddr;\r
649                                         phyAddr = (word)g_edid.CEC_C_D;  // Low-order nibbles\r
650                                         phyAddr |= ((word)g_edid.CEC_A_B << 8); // Hi-order nibbles\r
651                                         // Is the new PA different from the current PA?\r
652                                         if (phyAddr != SI_CecGetDevicePA ())\r
653                                         {\r
654                                                 // Yes!  So change the PA\r
655                                                 SI_CecSetDevicePA (phyAddr);\r
656                                         }\r
657                                 }\r
658 #endif\r
659 \r
660                 if ((DataIndex + 7) > VSDB_BaseOffset + DataBlockLength)        // Offset of 3D_Present bit in VSDB\r
661                         g_edid._3D_Supported = FALSE;\r
662                 else if (Data[DataIndex + 7] >> 7)\r
663                         g_edid._3D_Supported = TRUE;\r
664                 else\r
665                         g_edid._3D_Supported = FALSE;\r
666 \r
667                 DataIndex += DataBlockLength - HDMI_SIGNATURE_LEN - CEC_PHYS_ADDR_LEN; // Point to start of next block\r
668                 RK610_DBG(&client->dev,"EDID -> Short Descriptor Vendor Block\n");\r
669                 break;\r
670 \r
671             default:\r
672                 RK610_ERR(&client->dev,"EDID -> Unknown Tag Code\n");\r
673                 return EDID_UNKNOWN_TAG_CODE;\r
674 \r
675         }                   // End, Switch statement\r
676     }                       // End, while (DataIndex < LongDescriptorOffset) statement\r
677 \r
678     return EDID_SHORT_DESCRIPTORS_OK;\r
679 }\r
680 //------------------------------------------------------------------------------\r
681 // Function Name: ParseEDID()\r
682 // Function Description: Extract sink properties from its EDID file and save them in\r
683 //                  global structure g_edid.\r
684 //\r
685 // Accepts: none\r
686 // Returns: TRUE or FLASE\r
687 // Globals: EDID data\r
688 // NOTE: Fields that are not supported by the 9022/4 (such as deep color) were not parsed.\r
689 //------------------------------------------------------------------------------\r
690 static byte ParseEDID (struct i2c_client *client,byte *pEdid, byte *numExt)\r
691 {\r
692         if (!CheckEDID_Header(pEdid))\r
693         {\r
694                 // first 8 bytes of EDID must be {0, FF, FF, FF, FF, FF, FF, 0}\r
695                 RK610_ERR(&client->dev,"EDID -> Incorrect Header\n");\r
696                 return EDID_INCORRECT_HEADER;\r
697         }\r
698 \r
699         if (!DoEDID_Checksum(pEdid))\r
700         {\r
701                 // non-zero EDID checksum\r
702                 RK610_ERR(&client->dev,"EDID -> Checksum Error\n");\r
703                 return EDID_CHECKSUM_ERROR;\r
704         }\r
705 \r
706         *numExt = pEdid[NUM_OF_EXTEN_ADDR];     // read # of extensions from offset 0x7E of block 0\r
707         RK610_DBG(&client->dev,"EDID -> 861 Extensions = %d\n", (int) *numExt);\r
708 \r
709         if (!(*numExt))\r
710         {\r
711                 // No extensions to worry about\r
712                 RK610_DBG(&client->dev,"EDID -> EDID_NO_861_EXTENSIONS\n");\r
713                 return EDID_NO_861_EXTENSIONS;\r
714         }\r
715         return EDID_OK;\r
716 }\r
717 \r
718 int Rk610_Parse_resolution(void)\r
719 {\r
720     int i,vic;\r
721     memset(&Rk610_edid_result,0,sizeof(struct edid_result));\r
722     for(i=0;i < MAX_V_DESCRIPTORS;i++){\r
723         vic = g_edid.VideoDescriptor[i]&0x7f;\r
724         if(vic == HDMI_VIC_1080p_50Hz)\r
725             Rk610_edid_result.supported_1080p_50Hz = 1;\r
726         else if(vic == HDMI_VIC_1080p_60Hz)\r
727             Rk610_edid_result.supported_1080p_60Hz = 1; \r
728         else if(vic == HDMI_VIC_720p_50Hz)\r
729             Rk610_edid_result.supported_720p_50Hz = 1; \r
730         else if(vic == HDMI_VIC_720p_60Hz)\r
731             Rk610_edid_result.supported_720p_60Hz = 1; \r
732         else if(vic == HDMI_VIC_576p_50Hz)\r
733             Rk610_edid_result.supported_576p_50Hz = 1; \r
734         else if(vic == HDMI_VIC_480p_60Hz)\r
735             Rk610_edid_result.supported_720x480p_60Hz = 1; \r
736     }\r
737     #ifdef  RK610_DEBUG\r
738     printk("rk610_hdmi:1080p_50Hz %s\n",Rk610_edid_result.supported_1080p_50Hz?"support":"not support");\r
739     printk("rk610_hdmi:1080p_60Hz %s\n",Rk610_edid_result.supported_1080p_60Hz?"support":"not support");\r
740     printk("rk610_hdmi:720p_50Hz %s\n",Rk610_edid_result.supported_720p_50Hz?"support":"not support");\r
741     printk("rk610_hdmi:720p_60Hz %s\n",Rk610_edid_result.supported_720p_60Hz?"support":"not support");\r
742     printk("rk610_hdmi:576p_50Hz %s\n",Rk610_edid_result.supported_576p_50Hz?"support":"not support");\r
743     printk("rk610_hdmi:720x480p_60Hz %s\n",Rk610_edid_result.supported_720x480p_60Hz?"support":"not support");\r
744     #endif\r
745     return 0;\r
746 }\r
747 \r
748 int Rk610_Get_Optimal_resolution(int resolution_set)\r
749 {\r
750         int resolution_real;\r
751         int find_resolution = 0;\r
752         \r
753     Rk610_Parse_resolution();\r
754         switch(resolution_set){\r
755         case HDMI_1280x720p_50Hz:\r
756                 if(Rk610_edid_result.supported_720p_50Hz){\r
757                         resolution_real = HDMI_1280x720p_50Hz;\r
758                         find_resolution = 1;\r
759                 }\r
760                 break;\r
761         case HDMI_1280x720p_60Hz:\r
762                 if(Rk610_edid_result.supported_720p_60Hz){\r
763                         resolution_real = HDMI_1280x720p_60Hz;\r
764                         find_resolution = 1;\r
765                 }\r
766                 break;\r
767         case HDMI_720x576p_50Hz_4x3:\r
768                 if(Rk610_edid_result.supported_576p_50Hz){\r
769                         resolution_real = HDMI_720x576p_50Hz_4x3;\r
770                         find_resolution = 1;\r
771                 }\r
772                 break;\r
773         case HDMI_720x576p_50Hz_16x9:\r
774                 if(Rk610_edid_result.supported_576p_50Hz){\r
775                         resolution_real = HDMI_720x576p_50Hz_16x9;\r
776                         find_resolution = 1;\r
777                 }\r
778                 break;\r
779         case HDMI_720x480p_60Hz_4x3:\r
780                 if(Rk610_edid_result.supported_720x480p_60Hz){\r
781                         resolution_real = HDMI_720x480p_60Hz_4x3;\r
782                         find_resolution = 1;\r
783                 }\r
784                 break;\r
785         case HDMI_720x480p_60Hz_16x9:\r
786                 if(Rk610_edid_result.supported_720x480p_60Hz){\r
787                         resolution_real = HDMI_720x480p_60Hz_16x9;\r
788                         find_resolution = 1;\r
789                 }\r
790                 break;\r
791         case HDMI_1920x1080p_50Hz:\r
792                 if(Rk610_edid_result.supported_1080p_50Hz){\r
793                         resolution_real = HDMI_1920x1080p_50Hz;\r
794                         find_resolution = 1;\r
795                 }\r
796                 break;\r
797         case HDMI_1920x1080p_60Hz:\r
798                 if(Rk610_edid_result.supported_1080p_60Hz){\r
799                         resolution_real = HDMI_1920x1080p_60Hz;\r
800                         find_resolution = 1;\r
801                 }\r
802                 break;\r
803         default:\r
804                 break;\r
805         }\r
806 \r
807         if(find_resolution == 0){\r
808 \r
809                 if(Rk610_edid_result.supported_720p_50Hz)\r
810                         resolution_real = HDMI_1280x720p_50Hz;\r
811                 else if(Rk610_edid_result.supported_720p_60Hz)\r
812                         resolution_real = HDMI_1280x720p_60Hz;\r
813                 else if(Rk610_edid_result.supported_1080p_50Hz)\r
814                         resolution_real = HDMI_1920x1080p_50Hz;\r
815                 else if(Rk610_edid_result.supported_1080p_60Hz)\r
816                         resolution_real = HDMI_1920x1080p_60Hz;\r
817                 else if(Rk610_edid_result.supported_576p_50Hz)\r
818                         resolution_real = HDMI_720x576p_50Hz_4x3;\r
819                 else if(Rk610_edid_result.supported_720x480p_60Hz)\r
820                         resolution_real = HDMI_720x480p_60Hz_4x3;\r
821                 else\r
822                         resolution_real = HDMI_1280x720p_60Hz;\r
823         }\r
824 \r
825         return resolution_real;\r
826 }\r
827 \r
828 byte DoEdidRead (struct i2c_client *client)\r
829 {\r
830     u8 NumOfExtensions=0;\r
831     u8 Result;\r
832     u8 i,j;\r
833         // If we already have valid EDID data, ship this whole thing\r
834         if (g_edid.edidDataValid == FALSE)\r
835         {\r
836             Rk610_hdmi_sys_power_up(client);\r
837                 // Request access to DDC bus from the receiver\r
838         RK610_DDC_BUS_CONFIG(client);\r
839         memset(edid_buf,0,EDID_BLOCK_SIZE);\r
840                 RK610_read_edid_block(client,EDID_BLOCK0, edid_buf);            // read first 128 bytes of EDID ROM\r
841         RK610_DBG(&client->dev,"/************first block*******/\n");\r
842         #ifdef  RK610_DEBUG\r
843             for (j=0; j<EDID_BLOCK_SIZE; j++)\r
844                 {\r
845                     if(j%16==0)\r
846                         printk("\n%x :",j);\r
847                         printk("%2.2x ", edid_buf[j]);\r
848                 }\r
849             #endif\r
850         Result = ParseEDID(client,edid_buf, &NumOfExtensions);\r
851         if(Result!=EDID_OK){\r
852             if(Result==EDID_NO_861_EXTENSIONS){\r
853                 g_edid.HDMI_Sink = FALSE;\r
854             }\r
855             else {\r
856                 g_edid.HDMI_Sink = FALSE;\r
857                 return FALSE;\r
858             }\r
859         }\r
860             else{\r
861                 NumOfExtensions = edid_buf[NUM_OF_EXTEN_ADDR];\r
862                 for(i=1;i<=NumOfExtensions;i++){\r
863                 RK610_DBG(&client->dev,"\n/************block %d*******/\n",i);\r
864                 memset(edid_buf,0,EDID_BLOCK_SIZE);\r
865             RK610_read_edid_block(client,i, edid_buf); \r
866             Parse861ShortDescriptors(client,edid_buf);\r
867         #ifdef  RK610_DEBUG\r
868             for (j=0; j<EDID_BLOCK_SIZE; j++){\r
869                     if(j%16==0)\r
870                     printk("\n%x :",j);\r
871                     printk("%2.2X ", edid_buf[j]);\r
872                     }\r
873             #endif\r
874                 }\r
875 \r
876             g_edid.HDMI_Sink = TRUE;\r
877             }\r
878 \r
879 #if 0\r
880                 Result = ParseEDID(edid_buf, &NumOfExtensions);\r
881                         if (Result != EDID_OK)\r
882                         {\r
883                                 if (Result == EDID_NO_861_EXTENSIONS)\r
884                                 {\r
885                                         RK610_DBG(&client->dev,"EDID -> No 861 Extensions\n");\r
886                                         g_edid.HDMI_Sink = FALSE;\r
887                                         g_edid.YCbCr_4_4_4 = FALSE;\r
888                                         g_edid.YCbCr_4_2_2 = FALSE;\r
889                                         g_edid.CEC_A_B = 0x00;\r
890                                         g_edid.CEC_C_D = 0x00;\r
891                                 }\r
892                                 else\r
893                                 {\r
894                                         RK610_DBG(&client->dev,"EDID -> Parse FAILED\n");\r
895                                         g_edid.HDMI_Sink = TRUE;\r
896                                         g_edid.YCbCr_4_4_4 = FALSE;\r
897                                         g_edid.YCbCr_4_2_2 = FALSE;\r
898                                         g_edid.CEC_A_B = 0x00;\r
899                                         g_edid.CEC_C_D = 0x00;\r
900                                 }\r
901                         }\r
902                         else\r
903                         {\r
904                                 RK610_DBG(&client->dev,"EDID -> Parse OK\n");\r
905                                 Result = Parse861Extensions(NumOfExtensions);           // Parse 861 Extensions (short and long descriptors);\r
906                                 if (Result != EDID_OK)\r
907                                 {\r
908                                         RK610_DBG(&client->dev,"EDID -> Extension Parse FAILED\n");\r
909                                         g_edid.HDMI_Sink = FALSE;\r
910                                         g_edid.YCbCr_4_4_4 = FALSE;\r
911                                         g_edid.YCbCr_4_2_2 = FALSE;\r
912                                         g_edid.CEC_A_B = 0x00;\r
913                                         g_edid.CEC_C_D = 0x00;\r
914                                 }\r
915                                 else\r
916                                 {\r
917                                         RK610_DBG(&client->dev,"EDID -> Extension Parse OK\n");\r
918                                         g_edid.HDMI_Sink = TRUE;\r
919                                 }\r
920                         }\r
921 #endif\r
922                 RK610_DBG(&client->dev,"EDID -> NumOfExtensions = %d\n", NumOfExtensions);\r
923                 RK610_DBG(&client->dev,"EDID -> g_edid.HDMI_Sink = %d\n", (int)g_edid.HDMI_Sink);\r
924                 //RK610_DBG(&client->dev,"EDID -> g_edid.YCbCr_4_4_4 = %d\n", (int)g_edid.YCbCr_4_4_4);\r
925                 //RK610_DBG(&client->dev,"EDID -> g_edid.YCbCr_4_2_2 = %d\n", (int)g_edid.YCbCr_4_2_2);\r
926                 //RK610_DBG(&client->dev,"EDID -> g_edid.CEC_A_B = 0x%x\n", (int)g_edid.CEC_A_B);\r
927                 //RK610_DBG(&client->dev,"EDID -> g_edid.CEC_C_D = 0x%x\n", (int)g_edid.CEC_C_D);\r
928 \r
929                 g_edid.edidDataValid = TRUE;\r
930         }\r
931         return TRUE;\r
932 }\r
933 \r
934 static int Rk610_hdmi_Display_switch(struct i2c_client *client)\r
935 {\r
936     char c;\r
937     int ret=0;\r
938     int mode;\r
939     mode = (g_edid.HDMI_Sink == TRUE)? DISPLAY_HDMI:DISPLAY_DVI;\r
940     ret = Rk610_hdmi_i2c_read_p0_reg(client, 0x52, &c);\r
941     c &= ((~(1<<1))| mode<<1);\r
942     ret = Rk610_hdmi_i2c_write_p0_reg(client, 0x52, &c);\r
943     RK610_DBG(&client->dev,">>>%s mode=%d,c=%x",__func__,mode,c);\r
944     return ret;\r
945 }\r
946 \r
947 static int Rk610_hdmi_Config_audio_informat(struct i2c_client *client)\r
948 {\r
949     char c;\r
950     int ret=0;\r
951     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);\r
952     //Select configure for Audio Info\r
953     c=0x08;\r
954         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0x9f, &c);\r
955         //Configure the Audio info to HDMI RX.\r
956         c=0x84;     //HB0\r
957         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa0, &c);\r
958         c=0x01;     //HB1\r
959         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa1, &c);\r
960         c=0x0a;     //HB2\r
961         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa2, &c);\r
962         //c=0x00;   //PB0\r
963         //ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa3, &c);\r
964         c=0x11;     //PB1\r
965         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa4, &c);\r
966         c=0x09;     //PB2\r
967         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa5, &c);\r
968         c=0x00;     //PB3\r
969         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa6, &c);\r
970         c=0x00;     //PB4\r
971         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa7, &c);\r
972         c=0x01;     //PB5\r
973         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa8, &c);\r
974     return ret;\r
975 }\r
976 \r
977 static int Rk610_hdmi_Config_Avi_informat(struct i2c_client *client ,u8 vic)\r
978 {\r
979     char c;\r
980     int ret=0;\r
981     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);\r
982     //Select configure for AVI Info\r
983     c = 0x06;   \r
984         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0x9f, &c);\r
985 \r
986         //Configure the AVI info to HDMI RX\r
987         c = 0x82;   //HB0\r
988         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa0, &c);\r
989         c = 0x02;   //HB1\r
990         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa1, &c);\r
991         c = 0x0d;   //HB2\r
992         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa2, &c);\r
993         //c=0x00;   //PB0\r
994         //ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa3, &c);\r
995         c = 0x00;   //PB1\r
996         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa4, &c);\r
997         c = 0x08;   //PB2\r
998         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa5, &c);\r
999         c = 0x70;   //PB3\r
1000         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa6, &c);\r
1001         c = vic;    //PB4\r
1002         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa7, &c);\r
1003         c = 0x40;   //PB5\r
1004         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xa8, &c);\r
1005     return ret;\r
1006 }\r
1007 static int Rk610_hdmi_Config_Video(struct i2c_client *client, u8 video_format)\r
1008 {\r
1009     char vic;\r
1010     int ret = 0;\r
1011     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);\r
1012     switch(video_format){\r
1013                 case HDMI_720x480p_60Hz_4x3:\r
1014                 case HDMI_720x480p_60Hz_16x9:\r
1015                         vic = HDMI_VIC_480p_60Hz;\r
1016                         break;\r
1017         case HDMI_720x576p_50Hz_4x3:\r
1018         case HDMI_720x576p_50Hz_16x9:\r
1019             vic = HDMI_VIC_576p_50Hz;\r
1020             break;\r
1021                 case HDMI_1280x720p_50Hz:\r
1022                     vic = HDMI_VIC_720p_50Hz;\r
1023                         break;\r
1024                 case HDMI_1280x720p_60Hz:\r
1025                         vic = HDMI_VIC_720p_60Hz;\r
1026                         break;\r
1027                 case HDMI_1920x1080p_50Hz:\r
1028                     vic = HDMI_VIC_1080p_50Hz;\r
1029                         break;\r
1030                 case HDMI_1920x1080p_60Hz:\r
1031                         vic = HDMI_VIC_1080p_60Hz;\r
1032                         break;\r
1033                 default:\r
1034                         vic = 0x04;\r
1035                         break;\r
1036                 }\r
1037     ret = Rk610_hdmi_Config_Avi_informat(client,vic);\r
1038     return ret;\r
1039 }\r
1040 static int Rk610_hdmi_Config_Audio(struct i2c_client *client ,u8 audio_fs)\r
1041 {\r
1042     char c=0;\r
1043     int ret = 0;\r
1044     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);\r
1045     c=0x01;\r
1046         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0x35, &c);\r
1047         c=0x3c;\r
1048         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0x38, &c);\r
1049         c=0x00;\r
1050         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0x39, &c);\r
1051     c=0x18;\r
1052         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0x40, &c);\r
1053         switch(audio_fs){\r
1054         case HDMI_I2S_Fs_44100:\r
1055                 c=0x80;\r
1056                 ret = Rk610_hdmi_i2c_write_p0_reg(client, 0x41, &c);\r
1057                 break;\r
1058         case HDMI_I2S_Fs_48000:\r
1059             c=0x92;\r
1060                 ret = Rk610_hdmi_i2c_write_p0_reg(client, 0x41, &c);\r
1061                 break;\r
1062         default:\r
1063                 c=0x80;\r
1064                     ret = Rk610_hdmi_i2c_write_p0_reg(client, 0x41, &c);\r
1065             break;\r
1066         }\r
1067         Rk610_hdmi_Config_audio_informat(client);\r
1068         return ret;\r
1069 }\r
1070 \r
1071 int Rk610_hdmi_Set_Video(u8 video_format)\r
1072 {\r
1073     if(g_hw_inf.video_format !=video_format){\r
1074     g_hw_inf.video_format = video_format;\r
1075     g_hw_inf.config_param |= VIDEO_CHANGE;\r
1076     }\r
1077     return 0;\r
1078 }\r
1079 int Rk610_hdmi_Set_Audio(u8 audio_fs)\r
1080 {\r
1081     if(g_hw_inf.audio_fs !=audio_fs){\r
1082     g_hw_inf.audio_fs = audio_fs;\r
1083     g_hw_inf.config_param |= AUDIO_CHANGE;\r
1084     }\r
1085     return 0;\r
1086 }\r
1087 static int RK610_hdmi_Driver_mode(struct i2c_client *client)\r
1088 {\r
1089     char c;\r
1090     int ret=0;\r
1091     c=0x8e;\r
1092         ret =Rk610_hdmi_i2c_write_p0_reg(client, 0xe1, &c);\r
1093         c=0x04;\r
1094         ret =Rk610_hdmi_i2c_write_p0_reg(client, 0xe2, &c);\r
1095         return 0;\r
1096 }\r
1097 static int RK610_hdmi_PLL_mode(struct i2c_client *client)\r
1098 {\r
1099     char c;\r
1100     int ret=0;\r
1101     c=0x10;\r
1102         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xe8, &c);\r
1103         c=0x2c;\r
1104         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xe6, &c);\r
1105         c=0x00;\r
1106         ret = Rk610_hdmi_i2c_write_p0_reg(client, 0xe5, &c);\r
1107         return 0;\r
1108 }\r
1109 static void Rk610_hdmi_plug(struct i2c_client *client)\r
1110 {\r
1111     RK610_DBG(&client->dev,">>> hdmi plug \n");\r
1112         DoEdidRead(client);\r
1113         Rk610_hdmi_Display_switch(client);\r
1114         Rk610_hdmi_pwr_mode(client,LOWER_PWR);\r
1115         Rk610_hdmi_pwr_mode(client,NORMAL);\r
1116 }\r
1117 static void Rk610_hdmi_unplug(struct i2c_client *client)\r
1118 {\r
1119     RK610_DBG(&client->dev,">>> hdmi unplug \n");\r
1120         g_edid.edidDataValid = FALSE;\r
1121         Rk610_hdmi_pwr_mode(client,LOWER_PWR); \r
1122 }\r
1123 void Rk610_hdmi_event_work(struct i2c_client *client, bool *hpd)\r
1124 {\r
1125         char c=0;\r
1126         int ret=0;\r
1127     if(g_hw_inf.suspend_flag == 1){\r
1128         *hpd = 0;\r
1129         return ;\r
1130     }\r
1131 \r
1132         c=0x00;\r
1133         ret =Rk610_hdmi_i2c_read_p0_reg(client, 0xc1, &c);\r
1134         if(c & RK610_HPD_EVENT){\r
1135                 RK610_DBG(&client->dev,">>>HPD EVENT\n");\r
1136                 /**********clear hpd event******/\r
1137                 c = RK610_HPD_EVENT;\r
1138             ret =Rk610_hdmi_i2c_write_p0_reg(client, 0xc1, &c);\r
1139             ret =Rk610_hdmi_i2c_read_p0_reg(client, 0xc8, &c);\r
1140                 if(c & RK610_HPD_PLUG ){\r
1141             Rk610_hdmi_plug(client);\r
1142                         g_hw_inf.hpd=1;\r
1143                 }\r
1144                 else{\r
1145             Rk610_hdmi_unplug(client);\r
1146                         g_hw_inf.hpd=0;\r
1147                 }\r
1148 \r
1149         }\r
1150         if(c & RK610_EDID_EVENT){\r
1151                         /**********clear hpd event******/\r
1152                 c = RK610_EDID_EVENT;\r
1153             ret =Rk610_hdmi_i2c_write_p0_reg(client, 0xc1, &c);\r
1154                 RK610_DBG(&client->dev,">>>EDID EVENT\n");\r
1155                 /*************clear edid event*********/\r
1156         }\r
1157         *hpd = g_hw_inf.hpd;\r
1158 }\r
1159 int Rk610_hdmi_Config_Done(struct i2c_client *client)\r
1160 {\r
1161     char c;\r
1162     int ret=0;\r
1163     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);\r
1164 \r
1165     ret =Rk610_hdmi_sys_power_up(client);\r
1166 \r
1167     if(g_hw_inf.config_param != 0){\r
1168         c=0x08;\r
1169         ret =Rk610_hdmi_i2c_write_p0_reg(client, 0x04, &c);\r
1170         c=0x01;\r
1171         ret =Rk610_hdmi_i2c_write_p0_reg(client, 0x01, &c);\r
1172     if(g_hw_inf.config_param & VIDEO_CHANGE){\r
1173         Rk610_hdmi_Config_Video(client,g_hw_inf.video_format);\r
1174         g_hw_inf.config_param &= (~VIDEO_CHANGE); \r
1175     }\r
1176         if(g_hw_inf.config_param & AUDIO_CHANGE){\r
1177         Rk610_hdmi_Config_Audio(client,g_hw_inf.audio_fs);\r
1178         g_hw_inf.config_param &= (~AUDIO_CHANGE); \r
1179         }\r
1180     }\r
1181     ret =Rk610_hdmi_sys_power_down(client);\r
1182     ret =Rk610_hdmi_sys_power_up(client);\r
1183     ret =Rk610_hdmi_sys_power_down(client);\r
1184 \r
1185     return ret;\r
1186 }\r
1187 #if 0\r
1188 int Rk610_hdmi_hpd(struct i2c_client *client)\r
1189 {\r
1190     char c;\r
1191     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);\r
1192         if(Rk610_hdmi_i2c_read_p0_reg(client, 0xc8, &c)<0){\r
1193         RK610_ERR(">>>%s I2c trans err",__FUNCTION__);\r
1194         return -1;\r
1195         }\r
1196         if()\r
1197         return (c & RK610_HPD_PLUG)?1:0;\r
1198 }\r
1199 #endif\r
1200 static int RK610_hdmi_soft_reset(struct i2c_client *client)\r
1201 {\r
1202     char c;\r
1203     int ret;\r
1204     //soft reset\r
1205     c=0x00;\r
1206         ret =Rk610_hdmi_i2c_read_p0_reg(client, 0xce, &c);\r
1207         msleep(10);\r
1208         c=0x01;\r
1209         ret =Rk610_hdmi_i2c_read_p0_reg(client, 0xce, &c);      \r
1210         msleep(100);\r
1211         return ret;\r
1212 }\r
1213 static void Rk610_hdmi_Variable_Initial(void)\r
1214 {\r
1215     memset(&g_hw_inf,0,sizeof(struct rk610_hdmi_hw_inf));\r
1216     g_edid.edidDataValid = FALSE;\r
1217     g_hw_inf.edid_inf = &g_edid;    \r
1218     g_hw_inf.audio_fs = HDMI_I2S_DEFAULT_Fs;\r
1219     g_hw_inf.video_format = HDMI_DEFAULT_RESOLUTION;\r
1220     g_hw_inf.config_param = AUDIO_CHANGE | VIDEO_CHANGE;\r
1221     g_hw_inf.hpd = 0;\r
1222     g_hw_inf.suspend_flag = 0;\r
1223 \r
1224 }\r
1225 int Rk610_hdmi_init(struct i2c_client *client)\r
1226 {\r
1227     char c;\r
1228     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);\r
1229     Rk610_hdmi_Variable_Initial();\r
1230     RK610_hdmi_soft_reset(client);\r
1231     RK610_hdmi_Driver_mode(client);\r
1232     RK610_hdmi_PLL_mode(client);\r
1233         Rk610_hdmi_Set_Video(g_hw_inf.video_format);\r
1234         Rk610_hdmi_Set_Audio(g_hw_inf.audio_fs);\r
1235     Rk610_hdmi_Config_Done(client);\r
1236     \r
1237     Rk610_hdmi_i2c_read_p0_reg(client, 0xc8, &c);\r
1238     if(c & RK610_HPD_PLUG ){\r
1239         Rk610_hdmi_plug(client);\r
1240             g_hw_inf.hpd=1;\r
1241         }else{\r
1242         Rk610_hdmi_unplug(client);\r
1243             g_hw_inf.hpd=0;\r
1244         }\r
1245         return 0;\r
1246 }\r