• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18 #include "hdmi_hal_ddc.h"
19 #include "hdmi_osal.h"
20 #include "hdmi_reg_aon.h"
21 #include "hdmi_reg_ctrl.h"
22 #include "hdmi_hal_intf.h"
23 #include "hdmi_hal_ctrl.h"
24 #include "hdmi_product_define.h"
25 
26 #define DDC_EDID_SALVE_ADDR  0xa0
27 #define DDC_HDCP_SALVE_ADDR  0x74
28 #define DDC_SCDC_SALVE_ADDR  0xa8
29 #define DDC_MAX_FIFO_SIZE    16
30 #define DDC_EXT_BLOCK_OFFSET 0x7e
31 #define DDC_MAX_EDID_EXT_NUM 3    /* 3: 4(max block num) - 1(base block) */
32 #define DDC_DEFAULT_DELAY    8    /* 8us */
33 
34 static ddc_info g_ddc_info[HDMI_DEVICE_ID_BUTT];
35 
36 typedef enum {
37     DDC_CMD_READ_SINGLE_NO_ACK,
38     DDC_CMD_READ_SINGLE_ACK,
39     DDC_CMD_READ_MUTI_NO_ACK,
40     DDC_CMD_READ_MUTI_ACK,
41     DDC_CMD_READ_SEGMENT_NO_ACK,
42     DDC_CMD_READ_SEGMENT_ACK,
43     DDC_CMD_WRITE_MUTI_NO_ACK,
44     DDC_CMD_WRITE_MUTI_ACK,
45     DDC_CMD_FIFO_CLR = 0x09,
46     DDC_CMD_SCL_DRV,
47     DDC_CMD_MASTER_ABORT = 0x0f
48 } ddc_issue_cmd;
49 
ddc_info_ptr_get(hdmi_device_id hdmi)50 static ddc_info *ddc_info_ptr_get(hdmi_device_id hdmi)
51 {
52     if (hdmi < HDMI_DEVICE_ID_BUTT) {
53         return &g_ddc_info[hdmi];
54     }
55     return HI_NULL;
56 }
57 
ddc_access_enable_wait(hi_u32 timeout)58 static hi_s32 ddc_access_enable_wait(hi_u32 timeout)
59 {
60     hi_s32 ret = HI_SUCCESS;
61     hi_u32 tmp_time = 0;
62 
63     hdmi_reg_cpu_ddc_req_set(HI_TRUE);
64 
65     while (!hdmi_reg_cpu_ddc_req_ack_get()) {
66         osal_msleep(1);
67         tmp_time++;
68         if (tmp_time > timeout) {
69             ret = HI_FAILURE;
70             break;
71         }
72     }
73     return ret;
74 }
75 
ddc_access_disable_wait(hi_u32 timeout)76 static hi_s32 ddc_access_disable_wait(hi_u32 timeout)
77 {
78     hi_s32 ret = HI_SUCCESS;
79     hi_u32 tmp_time = 0;
80 
81     hdmi_reg_cpu_ddc_req_set(HI_FALSE);
82 
83     while (hdmi_reg_cpu_ddc_req_ack_get()) {
84         osal_msleep(1);
85         tmp_time += 1;
86         if (tmp_time > timeout) {
87             ret = HI_FAILURE;
88             break;
89         }
90     }
91     return ret;
92 }
93 
ddc_scl_wait(hi_u32 timeout)94 static hi_s32 ddc_scl_wait(hi_u32 timeout)
95 {
96     hi_s32 ret = HI_SUCCESS;
97     hi_u32 tmp_time = 0;
98 
99     while (!hdmi_reg_ddc_scl_st_get()) {
100         osal_msleep(1);
101         tmp_time += 1;
102         if (tmp_time > timeout) {
103             ret = HI_FAILURE;
104             break;
105         }
106     }
107     return ret;
108 }
109 
ddc_sda_wait(hi_u32 timeout)110 static hi_s32 ddc_sda_wait(hi_u32 timeout)
111 {
112     hi_u32 tmp_timeout = 0;
113     hi_s32 ret = HI_SUCCESS;
114 
115     if (!hdmi_reg_ddc_sda_st_get()) {
116         hdmi_reg_dcc_man_en_set(HI_TRUE);
117         while ((!hdmi_reg_ddc_sda_st_get()) && tmp_timeout++ < timeout) {
118             /* pull scl high */
119             hdmi_reg_ddc_scl_oen_set(HI_TRUE);
120             osal_udelay(DDC_DEFAULT_DELAY);
121             /* pull scl low */
122             hdmi_reg_ddc_scl_oen_set(HI_FALSE);
123             osal_udelay(DDC_DEFAULT_DELAY);
124         }
125 
126         /* STOP contition */
127         if (tmp_timeout < timeout && (hdmi_reg_ddc_sda_st_get())) {
128             /* pull sda low */
129             hdmi_reg_ddc_sda_oen_set(HI_FALSE);
130             osal_udelay(DDC_DEFAULT_DELAY);
131             /* pull scl high */
132             hdmi_reg_ddc_scl_oen_set(HI_TRUE);
133             osal_udelay(DDC_DEFAULT_DELAY);
134             /* pull sda high */
135             hdmi_reg_ddc_sda_oen_set(HI_TRUE);
136             osal_udelay(DDC_DEFAULT_DELAY);
137             hdmi_info("deadlock clear success\n");
138             ret = HI_SUCCESS;
139         } else {
140             hdmi_warn("deadlock clear fail\n");
141             ret = HI_FAILURE;
142         }
143         hdmi_reg_dcc_man_en_set(HI_FALSE);
144     }
145 
146     return ret;
147 }
148 
ddc_in_prog_wait(hi_u32 timeout)149 static hi_s32 ddc_in_prog_wait(hi_u32 timeout)
150 {
151     hi_s32 ret = HI_SUCCESS;
152     hi_u32 tmp_time = 0;
153 
154     while (hdmi_reg_pwd_i2c_in_prog_get()) {
155         osal_msleep(1);
156         tmp_time += 1;
157         if (tmp_time > timeout) {
158             ret = HI_FAILURE;
159             break;
160         }
161     }
162 
163     return ret;
164 }
165 
ddc_cmd_issue(const ddc_cfg * cfg)166 static hi_s32 ddc_cmd_issue(const ddc_cfg *cfg)
167 {
168     hi_u32 slave_addr = 0;
169     hi_u32 segment, offset, data_size;
170 
171     segment   = cfg->segment;
172     offset    = cfg->offset;
173     data_size = cfg->data_size;
174 
175     switch (cfg->func_type) {
176         case DDC_FUNC_TYPE_EDID:
177             slave_addr = DDC_EDID_SALVE_ADDR;
178             break;
179         case DDC_FUNC_TYPE_HDCP:
180             slave_addr = DDC_HDCP_SALVE_ADDR;
181             break;
182         case DDC_FUNC_TYPE_SCDC:
183             slave_addr = DDC_SCDC_SALVE_ADDR;
184             break;
185         default:
186             hdmi_warn("un-known DDC function type, wrong slaveaddr!\n");
187             break;
188     }
189 
190     if (cfg->master_mode == DDC_MASTER_MODE_PWD) {
191         hdmi_reg_pwd_mst_cmd_set(DDC_CMD_FIFO_CLR);
192         hdmi_reg_pwd_slave_addr_set(slave_addr);
193         hdmi_reg_pwd_slave_seg_set(segment);
194         hdmi_reg_pwd_slave_offset_set(offset);
195         hdmi_reg_pwd_data_out_cnt_set(data_size);
196         osal_udelay(DDC_DEFAULT_DELAY);
197         hdmi_reg_pwd_mst_cmd_set(cfg->issue_mode);
198     } else {
199         hdmi_err("unknown master_mode=%u\n", cfg->master_mode);
200     }
201 
202     return HI_SUCCESS;
203 }
204 
ddc_read(ddc_cfg * cfg)205 static hi_s32 ddc_read(ddc_cfg *cfg)
206 {
207     hi_u32 len;
208     ddc_func_type type;
209     hi_u8 *data = HI_NULL;
210     hi_u32 i, retry, data_size;
211     hi_u32 time_start, time_curr;
212 
213     data  = cfg->data;
214     type  = cfg->func_type;
215     len   = cfg->data_size;
216     retry = cfg->issue_timeout < DDC_DEFAULT_TIMEOUT_ISSUE ? DDC_DEFAULT_TIMEOUT_ISSUE : cfg->sda_timeout;
217 
218     for (data_size = 0; data_size < len; data_size++, data++) {
219         /* maybe msleep(1) cost 20ms, 30 times, total 600ms. */
220         time_start = hdmi_osal_get_time_in_ms();
221         time_curr  = time_start;
222         /* when read-fifo empty, every byte wait a max timeout */
223         for (i = 0;
224              ((i < retry) && (hdmi_reg_pwd_fifo_empty_get() || (hdmi_reg_pwd_fifo_data_out_get() == 0))) &&
225              ((time_curr - time_start) <= DDC_DEFAULT_RETRY_TIMEOUT_ISSUE);
226              i++) {
227             /* wait ddc status update after DDC cmd set. */
228             osal_msleep(1);
229             if (hdmi_reg_ddc_i2c_no_ack_get() || hdmi_reg_ddc_i2c_bus_low_get()) {
230                 hdmi_reg_pwd_mst_cmd_set(DDC_CMD_MASTER_ABORT);
231                 hdmi_warn("DDC status error!\n");
232                 return HI_FAILURE;
233             }
234             time_curr = hdmi_osal_get_time_in_ms();
235         }
236         if ((i >= retry) || ((time_curr - time_start) > DDC_DEFAULT_RETRY_TIMEOUT_ISSUE)) {
237             if (type != DDC_FUNC_TYPE_SCDC) {
238                 hdmi_warn("read fifo retry=%u ms, size=%u, timeout:%u!\n",
239                           retry, len, (time_curr - time_start));
240             } else {
241                 hdmi_info("read fifo retry=%u ms, size=%u, timeout:%u!\n",
242                           retry, len, (time_curr - time_start));
243             }
244             return HI_FAILURE;
245         }
246         if (data != HI_NULL) {
247             *data = hdmi_reg_rdata_pwd_fifo_data_out_get();
248             /*
249              * the fifo status is not refresh promptly,
250              * so re-read the fifo status and delay 1us if the fifo is empty,
251              * wait the data ready. it must delay 1us after read fifo data.
252              */
253             osal_udelay(1);
254         } else {
255             hdmi_err("edid &data[%u]=null\n", data_size);
256             return HI_FAILURE;
257         }
258     }
259 
260     return data_size;
261 }
262 
ddc_write(ddc_cfg * cfg)263 static hi_s32 ddc_write(ddc_cfg *cfg)
264 {
265     hi_u32 len;
266     ddc_func_type type;
267     hi_u8 *data = HI_NULL;
268     hi_u32 i, retry, data_size;
269     hi_u32 time_start, time_curr;
270 
271     data  = cfg->data;
272     type  = cfg->func_type;
273     len   = cfg->data_size;
274     retry = cfg->issue_timeout < DDC_DEFAULT_TIMEOUT_ISSUE ? DDC_DEFAULT_TIMEOUT_ISSUE : cfg->sda_timeout;
275 
276     for (data_size = 0; data_size < len; data_size++, data++) {
277         /* maybe msleep(1) cost 20ms, every byte wait a max timeout 60ms. */
278         time_start = hdmi_osal_get_time_in_ms();
279         time_curr = time_start;
280         /* when write-fifo full, every byte wait a max timeout and retry times */
281         for (i = 0;
282              (((i < retry) && (hdmi_reg_pwd_fifo_data_out_get() >= DDC_MAX_FIFO_SIZE)) &&
283               ((time_curr - time_start) <= DDC_DEFAULT_RETRY_TIMEOUT_ISSUE));
284              i++) {
285             /* wait ddc status update after DDC cmd set. */
286             osal_msleep(1);
287             if (hdmi_reg_ddc_i2c_no_ack_get() || hdmi_reg_ddc_i2c_bus_low_get()) {
288                 hdmi_reg_pwd_mst_cmd_set(DDC_CMD_MASTER_ABORT);
289                 hdmi_warn("DDC status error!\n");
290                 return HI_FAILURE;
291             }
292             time_curr = hdmi_osal_get_time_in_ms();
293         }
294         if (i >= retry || ((time_curr - time_start) > DDC_DEFAULT_RETRY_TIMEOUT_ISSUE)) {
295             if (type != DDC_FUNC_TYPE_SCDC) {
296                 hdmi_err("write fifo retry=%u ms, size=%u, timeout:%u!\n",
297                          retry, len, (time_curr - time_start));
298             } else {
299                 hdmi_info("write fifo retry=%u ms, size=%u, timeout:%u!\n",
300                           retry, len, (time_curr - time_start));
301             }
302             return HI_FAILURE;
303         }
304 
305         if (data != HI_NULL) {
306             hdmi_reg_pwd_fifo_data_in_set(*data);
307             osal_udelay(1);
308         } else {
309             hdmi_err("edid &data[%u]=null\n", data_size);
310             return HI_FAILURE;
311         }
312     }
313 
314     return data_size;
315 }
316 
ddc_data_pwd_issue(ddc_cfg * cfg,hi_bool read_issue)317 static hi_s32 ddc_data_pwd_issue(ddc_cfg *cfg, hi_bool read_issue)
318 {
319     hi_s32 data_size;
320 
321     if (read_issue) {
322         /* read issue */
323         data_size = ddc_read(cfg);
324     } else {
325         /* write issue */
326         data_size = ddc_write(cfg);
327     }
328 
329     return data_size;
330 }
331 
ddc_data_issue(ddc_cfg * cfg,hi_bool read_issue)332 static hi_s32 ddc_data_issue(ddc_cfg *cfg, hi_bool read_issue)
333 {
334     if (cfg->master_mode == DDC_MASTER_MODE_PWD) {
335         return ddc_data_pwd_issue(cfg, read_issue);
336     } else {
337         hdmi_err("unknown master_mode=%u,fail!\n", cfg->master_mode);
338         return HI_FAILURE;
339     }
340 }
341 
ddc_err_clean_check(hdmi_device_id hdmi)342 static hi_s32 ddc_err_clean_check(hdmi_device_id hdmi)
343 {
344     hi_s32 ret = HI_SUCCESS;
345     ddc_info *tmp = ddc_info_ptr_get(hdmi);
346 
347     hdmi_if_null_warn_return(tmp, HI_FAILURE);
348     hdmi_if_false_warn_return(tmp->run.init, HI_FAILURE);
349 
350     /* in prog check */
351     if (ddc_in_prog_wait(DDC_DEFAULT_TIMEOUT_IN_PROG) != HI_SUCCESS) {
352         hdmi_warn("error clr, wait in prog timeout!\n");
353         ret = HI_FAILURE;
354     }
355     /* scl check */
356     if (ddc_scl_wait(DDC_DEFAULT_TIMEOUT_SCL) != HI_SUCCESS) {
357         hdmi_warn("error clr, wait scl timeout!\n");
358         ret = HI_FAILURE;
359     }
360     /* sda check */
361     if (ddc_sda_wait(DDC_DEFAULT_TIMEOUT_SDA) != HI_SUCCESS) {
362         hdmi_warn("error clr, wait sda timeout!\n");
363         ret = HI_FAILURE;
364     }
365     if (ret == HI_SUCCESS) {
366         hdmi_info("error clr success!\n");
367     }
368 
369     return ret;
370 }
371 
ddc_reset(hdmi_device_id hdmi)372 static hi_s32 ddc_reset(hdmi_device_id hdmi)
373 {
374     hi_u32 i;
375     ddc_record_elem *tmp_elem = HI_NULL;
376     ddc_info *tmp = ddc_info_ptr_get(hdmi);
377 
378     hdmi_if_null_warn_return(tmp, HI_FAILURE);
379     hdmi_if_false_warn_return(tmp->run.init, HI_FAILURE);
380 
381     for (i = 0; i < DDC_MAX_RECORD_NUM; i++) {
382         tmp_elem = &tmp->ddc_record[i];
383         if (tmp_elem->data != HI_NULL) {
384             osal_vfree(tmp_elem->data);
385         }
386         (hi_void)memset_s(tmp_elem, sizeof(tmp->ddc_record[i]), 0, sizeof(ddc_record_elem));
387     }
388 
389     tmp->run.elem_ptr  = 0;
390     tmp->run.total_num = 0;
391 
392     return ddc_err_clean_check(hdmi);
393 }
394 
ddc_issue(ddc_cfg * cfg,ddc_record_elem * tmp_elem)395 static hi_s32 ddc_issue(ddc_cfg *cfg, ddc_record_elem *tmp_elem)
396 {
397     hi_s32 ret = HI_SUCCESS;
398     hi_bool read_issue = HI_FALSE;
399 
400     /* access check */
401     if (cfg->master_mode == DDC_MASTER_MODE_PWD) {
402         if (ddc_access_enable_wait(cfg->access_timeout) != HI_SUCCESS) {
403             hdmi_err("wait access bus timeout!\n");
404             tmp_elem->un_err.u32.access_wait_timeout = HI_TRUE;
405             return ret;
406         }
407     }
408     /* scl check */
409     if (ddc_scl_wait(cfg->scl_timeout) != HI_SUCCESS) {
410         hdmi_err("wait scl timeout!\n");
411         tmp_elem->un_err.u32.bus_low_scl = HI_TRUE;
412         return ret;
413     }
414     /* sda check */
415     if (ddc_sda_wait(cfg->sda_timeout) != HI_SUCCESS) {
416         hdmi_err("wait sda timeout!\n");
417         tmp_elem->un_err.u32.bus_low_sda = HI_TRUE;
418         return ret;
419     }
420     /* jude read/write issue */
421     if (cfg->issue_mode <= DDC_MODE_READ_SEGMENT_ACK) {
422         read_issue = HI_TRUE;
423     } else if (cfg->issue_mode < DDC_MODE_BUTT) {
424         read_issue = HI_FALSE;
425     } else {
426         hdmi_err("un-known ddc issue mode!\n");
427         tmp_elem->un_err.u32.err_isseu_mode = HI_TRUE;
428         return ret;
429     }
430     /* issue command */
431     if (ddc_cmd_issue(cfg) != HI_SUCCESS) {
432         hdmi_err("command issue fail!\n");
433         return ret;
434     }
435     /* issue data */
436     ret = ddc_data_issue(cfg, read_issue);
437     if (ret <= 0) {
438         hdmi_info("data issue fail!\n");
439         tmp_elem->un_err.u32.issue_timeout = HI_TRUE;
440         return ret;
441     }
442 
443     return ret;
444 }
445 
hal_hdmi_ddc_init(hdmi_device_id hdmi)446 hi_s32 hal_hdmi_ddc_init(hdmi_device_id hdmi)
447 {
448     ddc_info *tmp = ddc_info_ptr_get(hdmi);
449 
450     hdmi_if_null_warn_return(tmp, HI_FAILURE);
451 
452     if (!tmp->run.init) {
453         osal_sema_init(&tmp->ddc_wr_mutex, 1);
454         (hi_void)memset_s(tmp->ddc_record, sizeof(tmp->ddc_record), 0, sizeof(tmp->ddc_record));
455         tmp->run.init = HI_TRUE;
456         tmp->run.elem_ptr = 0;
457         tmp->run.total_num = 0;
458     }
459 
460     return HI_SUCCESS;
461 }
462 
hal_hdmi_ddc_deinit(hdmi_device_id hdmi)463 hi_s32 hal_hdmi_ddc_deinit(hdmi_device_id hdmi)
464 {
465     ddc_info *tmp = ddc_info_ptr_get(hdmi);
466 
467     hdmi_if_null_warn_return(tmp, HI_FAILURE);
468     hdmi_if_false_warn_return(tmp->run.init, HI_FAILURE);
469 
470     ddc_reset(hdmi);
471     osal_sema_destroy(&tmp->ddc_wr_mutex);
472     tmp->run.init = HI_FALSE;
473 
474     return HI_SUCCESS;
475 }
476 
hal_hdmi_ddc_issue(hdmi_device_id hdmi,ddc_cfg * cfg)477 hi_s32 hal_hdmi_ddc_issue(hdmi_device_id hdmi, ddc_cfg *cfg)
478 {
479     errno_t errnumber;
480     hi_s32 ret;
481     ddc_record_elem *tmp_elem = HI_NULL;
482     ddc_info        *tmp = ddc_info_ptr_get(hdmi);
483 
484     hdmi_if_null_warn_return(cfg, HI_FAILURE);
485     hdmi_if_null_warn_return(tmp, HI_FAILURE);
486     hdmi_if_false_warn_return(tmp->run.init, HI_FAILURE);
487 
488     tmp->run.elem_ptr = (1 + tmp->run.elem_ptr) % DDC_MAX_RECORD_NUM;
489     if (tmp->run.total_num <= DDC_MAX_RECORD_NUM) {
490         tmp->run.total_num++;
491     }
492     tmp_elem = &tmp->ddc_record[tmp->run.elem_ptr];
493     (hi_void)memset_s(tmp_elem, sizeof(tmp->ddc_record[tmp->run.elem_ptr]), 0, sizeof(ddc_record_elem));
494     errnumber = memcpy_s(&tmp_elem->cfg, sizeof(tmp_elem->cfg), cfg, sizeof(ddc_cfg));
495     hdmi_unequal_eok_return(errnumber, HI_ERR_HDMI_INVALID_PARA);
496     tmp_elem->start_time = hal_hdmi_mach_ms_get();
497 
498     hdmi_mutex_lock(tmp->ddc_wr_mutex);
499     ret = ddc_issue(cfg, tmp_elem);
500     /* in prog check */
501     if (ddc_in_prog_wait(cfg->in_prog_timeout) != HI_SUCCESS) {
502         hdmi_warn("wait in prog timeout!\n");
503         tmp_elem->un_err.u32.in_prog_timeout = HI_TRUE;
504     }
505     if (tmp_elem->un_err.word) {
506         hdmi_hpd_rsen hpd = {0};
507         hal_hdmi_ctrl_hpd_rsen_get(hdmi, &hpd);
508         if (!hpd.hpd_on) {
509             hdmi_warn("hpd no exist!\n");
510             tmp_elem->un_err.u32.hpd_no_exist = HI_TRUE;
511         } else if (ddc_err_clean_check(hdmi) != HI_SUCCESS) {
512             hdmi_warn("error clear fail!\n");
513             tmp_elem->un_err.u32.clr_err_fail = 1;
514         }
515     }
516     if (cfg->master_mode == DDC_MASTER_MODE_PWD) {
517         if (ddc_access_disable_wait(cfg->access_timeout) != HI_SUCCESS) {
518             hdmi_warn("wait access disable timeout!\n");
519         }
520     }
521     tmp_elem->time_len = hal_hdmi_mach_ms_get() - tmp_elem->start_time;
522     hdmi_mutex_unlock(tmp->ddc_wr_mutex);
523 
524     return ret;
525 }
526 
hal_hdmi_ddc_default_cfg_get(hdmi_device_id hdmi,ddc_cfg * cfg)527 hi_void hal_hdmi_ddc_default_cfg_get(hdmi_device_id hdmi, ddc_cfg *cfg)
528 {
529     ddc_info *tmp = ddc_info_ptr_get(hdmi);
530 
531     hdmi_if_null_warn_return_void(tmp);
532     hdmi_if_null_warn_return_void(cfg);
533     hdmi_if_false_warn_return_void(tmp->run.init);
534 
535     cfg->segment         = 0;
536     cfg->offset          = 0;
537     cfg->func_type       = DDC_FUNC_TYPE_EDID;
538     cfg->issue_mode      = DDC_MODE_READ_MUTIL_NO_ACK;
539     cfg->speed           = 0;
540     cfg->master_mode     = DDC_MASTER_MODE_PWD;
541     cfg->access_timeout  = DDC_DEFAULT_TIMEOUT_ACCESS;
542     cfg->hpd_timeout     = DDC_DEFAULT_TIMEOUT_HPD;
543     cfg->in_prog_timeout = DDC_DEFAULT_TIMEOUT_IN_PROG;
544     cfg->scl_timeout     = DDC_DEFAULT_TIMEOUT_SCL;
545     cfg->sda_timeout     = DDC_DEFAULT_TIMEOUT_SDA;
546     cfg->issue_timeout   = DDC_DEFAULT_TIMEOUT_ISSUE;
547     cfg->data_size       = 0;
548     cfg->data            = HI_NULL;
549 
550     return;
551 }
552 
edid_get_extern_blk(hdmi_device_id hdmi,const hi_u8 ext_blk_num,const hi_s32 raw_len,ddc_cfg * cfg)553 static hi_s32 edid_get_extern_blk(hdmi_device_id hdmi, const hi_u8 ext_blk_num, const hi_s32 raw_len, ddc_cfg *cfg)
554 {
555     hi_s32 ret = raw_len;
556 
557     cfg->data      += cfg->data_size;
558     cfg->offset     = 0;
559     cfg->issue_mode = DDC_MODE_READ_SEGMENT_NO_ACK;
560     cfg->segment    = 1;
561     cfg->data_size  = HDMI_EDID_BLOCK_SIZE * ext_blk_num;
562     ret += hal_hdmi_ddc_issue(hdmi, cfg);
563     if (ret > 0) {
564         hdmi_info("EDID read EXT-block 2~%u success!\n", ext_blk_num + 1);
565     } else {
566         hdmi_warn("EDID read EXT-block 2~%u fail!\n", ext_blk_num + 1);
567     }
568 
569     return ret;
570 }
571 
hal_hdmi_ddc_edid_raw_get(hdmi_device_id hdmi,hi_s32 size,hi_u8 * data)572 hi_s32 hal_hdmi_ddc_edid_raw_get(hdmi_device_id hdmi, hi_s32 size, hi_u8 *data)
573 {
574     hi_u8 ext_block_num, des_block_num;
575     hi_s32 ret;
576     ddc_cfg cfg = {0};
577 
578     hdmi_if_null_warn_return(data, HI_FAILURE);
579 
580     hal_hdmi_ddc_default_cfg_get(hdmi, &cfg);
581     cfg.segment    = 0;
582     cfg.func_type  = DDC_FUNC_TYPE_EDID;
583     cfg.issue_mode = DDC_MODE_READ_MUTIL_NO_ACK;
584     cfg.data_size  = HDMI_EDID_BLOCK_SIZE;
585     cfg.data       = &data[0];
586     ret = hal_hdmi_ddc_issue(hdmi, &cfg);
587     /* block 0 */
588     if (ret <= 0) {
589         hdmi_warn("edid block 0 read fail!\n");
590         return ret;
591     }
592     hdmi_info("EDID block 0 read success!\n");
593 
594     ext_block_num = data[DDC_EXT_BLOCK_OFFSET];
595     if (ext_block_num > DDC_MAX_EDID_EXT_NUM) {
596         hdmi_warn("sink edid blocks num=%u, but we only support %u\n", ext_block_num, DDC_MAX_EDID_EXT_NUM);
597         ext_block_num = DDC_MAX_EDID_EXT_NUM;
598     }
599 
600     des_block_num = (size / HDMI_EDID_BLOCK_SIZE) - 1;
601     if (ext_block_num > des_block_num) {
602         hdmi_warn("scr block num > des block num, adapt ext_block_num to %u\n", des_block_num);
603         ext_block_num = des_block_num;
604     }
605     if (ext_block_num == 0) {
606         hdmi_warn("edid block 0 read fail!\n");
607         return ret;
608     }
609     /* block 1 */
610     cfg.data += cfg.data_size;
611     cfg.offset = HDMI_EDID_BLOCK_SIZE;
612     ret += hal_hdmi_ddc_issue(hdmi, &cfg);
613     if (ret > 0) {
614         hdmi_info("EDID EXT-block 1 read success!\n");
615         ext_block_num--;
616         if (ext_block_num) {
617             /* block 2&3 */
618             ret = edid_get_extern_blk(hdmi, ext_block_num, ret, &cfg);
619         }
620     } else {
621         hdmi_warn("EDID EXT-block 1 read fail!\n");
622     }
623 
624     return ret;
625 }
626 
627