hdmirx: add edid data splice function [1/1]
authorHang Cheng <hang.cheng@amlogic.com>
Thu, 16 May 2019 02:20:08 +0000 (10:20 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Fri, 31 May 2019 16:21:40 +0000 (09:21 -0700)
PD#SWPL-8467

Problem:
1.no index parse for edid data block
2.no earc capabilities data structure parse
3.no earc cap data structure splice function
4.no cta data block splice/remove function

Solution:
1.add edid data block index parse
2.add earc capabilities data structure parse
3.add splice function of earc cap data structure
4.add splice/remove function of data block to edid

Verify:
TL1

Change-Id: I47b9f2176c31c65a08cdc657c00398f88cbdd7d3
Signed-off-by: Hang Cheng <hang.cheng@amlogic.com>
drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_drv.c
drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_drv.h
drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_edid.c
drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_edid.h
drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_wrapper.c

index 06f7322..d22d90b 100644 (file)
@@ -1622,6 +1622,43 @@ static ssize_t get_reset_hdcp22(struct device *dev,
 {
        return 0;
 }
+
+static ssize_t earc_cap_ds_show(struct device *dev,
+       struct device_attribute *attr,
+       char *buf)
+{
+       return 0;
+}
+
+static ssize_t earc_cap_ds_store(struct device *dev,
+       struct device_attribute *attr,
+       const char *buf, size_t count)
+{
+       unsigned char char_len = 0;
+       unsigned int data = 0;
+       unsigned char i = 0;
+       unsigned char tmp[3] = {0};
+       unsigned char earc_cap_ds[EARC_CAP_DS_MAX_LENGTH] = {0};
+       int ret = 0;
+
+       char_len = strlen(buf);
+       rx_pr("character length = %d\n", char_len);
+       for (i = 0; i < char_len/2; i++) {
+               tmp[2] = '\0';
+               memcpy(tmp, buf + 2*i, 2);
+               ret = kstrtouint(tmp, 16, &data);
+               if (ret < 0) {
+                       rx_pr("kstrtouint failed\n");
+                       return count;
+               }
+               earc_cap_ds[i] = data;
+       }
+       rx_pr("eARC cap ds len: %d\n", i);
+       rx_set_earc_cap_ds(earc_cap_ds, i);
+
+       return count;
+}
+
 static DEVICE_ATTR(debug, 0644, hdmirx_debug_show, hdmirx_debug_store);
 static DEVICE_ATTR(edid, 0644, hdmirx_edid_show, hdmirx_edid_store);
 static DEVICE_ATTR(key, 0644, hdmirx_key_show, hdmirx_key_store);
@@ -1637,6 +1674,7 @@ static DEVICE_ATTR(hdcp_version, 0644, hdcp_version_show, hdcp_version_store);
 static DEVICE_ATTR(hw_info, 0644, hw_info_show, hw_info_store);
 static DEVICE_ATTR(edid_dw, 0644, edid_dw_show, edid_dw_store);
 static DEVICE_ATTR(ksvlist, 0644, ksvlist_show, ksvlist_store);
+static DEVICE_ATTR(earc_cap_ds, 0644, earc_cap_ds_show, earc_cap_ds_store);
 
 static int hdmirx_add_cdev(struct cdev *cdevp,
                const struct file_operations *fops,
@@ -2162,6 +2200,11 @@ static int hdmirx_probe(struct platform_device *pdev)
                rx_pr("hdmirx: fail to create ksvlist file\n");
                goto fail_create_ksvlist;
        }
+       ret = device_create_file(hdevp->dev, &dev_attr_earc_cap_ds);
+       if (ret < 0) {
+               rx_pr("hdmirx: fail to create earc_cap_ds file\n");
+               goto fail_create_earc_cap_ds;
+       }
 
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
@@ -2353,7 +2396,13 @@ static int hdmirx_probe(struct platform_device *pdev)
                disable_port_en = (disable_port >> 4) & 0x1;
                disable_port_num = disable_port & 0xF;
        }
-
+       ret = of_property_read_u32(pdev->dev.of_node,
+               "arc_port", &rx.arc_port);
+       if (ret) {
+               /* default arc port is port B */
+               rx.arc_port = 0x1;
+               rx_pr("not find arc_port, portB by default\n");
+       }
        ret = of_reserved_mem_device_init(&(pdev->dev));
        if (ret != 0)
                rx_pr("warning: no rev cmd mem\n");
@@ -2380,6 +2429,8 @@ fail_kmalloc_pd_fifo:
        return ret;
 fail_get_resource_irq:
        return ret;
+fail_create_earc_cap_ds:
+       device_remove_file(hdevp->dev, &dev_attr_earc_cap_ds);
 fail_create_ksvlist:
        device_remove_file(hdevp->dev, &dev_attr_ksvlist);
 fail_create_edid_dw:
@@ -2447,6 +2498,7 @@ static int hdmirx_remove(struct platform_device *pdev)
        device_remove_file(hdevp->dev, &dev_attr_esm_base);
        device_remove_file(hdevp->dev, &dev_attr_info);
        device_remove_file(hdevp->dev, &dev_attr_arc_aud_type);
+       device_remove_file(hdevp->dev, &dev_attr_earc_cap_ds);
        device_remove_file(hdevp->dev, &dev_attr_ksvlist);
        device_remove_file(hdevp->dev, &dev_attr_edid_dw);
        device_remove_file(hdevp->dev, &dev_attr_hw_info);
index be4d203..6524b32 100644 (file)
@@ -46,7 +46,7 @@
  *
  *
  */
-#define RX_VER2 "ver.2019/05/08"
+#define RX_VER2 "ver.2019/05/18"
 
 /*print type*/
 #define        LOG_EN          0x01
@@ -449,6 +449,7 @@ struct rx_s {
        /*struct pd_infoframe_s dbg_info;*/
        struct phy_sts phy;
        struct emp_buff empbuff;
+       uint32_t arc_port;
 };
 
 struct _hdcp_ksv {
index dad96ab..9ce09bf 100644 (file)
@@ -35,7 +35,7 @@
 #include "hdmi_rx_edid.h"
 #include "hdmi_rx_hw.h"
 
-static unsigned char edid_temp[EDID_SIZE];
+unsigned char edid_temp[EDID_SIZE];
 static char edid_buf[MAX_EDID_BUF_SIZE] = {0x0};
 static int edid_size;
 struct edid_data_s tmp_edid_data;
@@ -43,6 +43,11 @@ int arc_port_id;
 bool need_support_atmos_bit;
 static unsigned char receive_hdr_lum[3];
 
+static unsigned int earc_cap_ds_len;
+static unsigned char recv_earc_cap_ds[EARC_CAP_DS_MAX_LENGTH] = {0};
+bool new_earc_cap_ds;
+static uint8_t com_aud[DB_LEN_MAX-1] = {0};
+
 int edid_mode;
 int port_map = 0x4231;
 MODULE_PARM_DESC(port_map, "\n port_map\n");
@@ -57,6 +62,15 @@ module_param(new_hdr_lum, bool, 0664);
  * 0:not reset hpd after atmos edid update
  */
 bool atmos_edid_update_hpd_en = 1;
+/* if free space is not enough in edid to do
+ * data blk splice, then remove the last dtd(s)
+ */
+bool en_take_dtd_space = true;
+/*
+ * 1:reset hpd after cap ds edid update
+ * 0:not reset hpd after cap ds edid update
+ */
+bool earc_cap_ds_update_hpd_en = true;
 
 
 /* hdmi1.4 edid */
@@ -425,6 +439,105 @@ unsigned char *edid_list[] = {
        edid_20,
 };
 
+static struct cta_blk_pair cta_blk[] = {
+       {
+               .tag_code = AUDIO_TAG,
+               .blk_name = "Audio_DB",
+       },
+       {
+               .tag_code = VIDEO_TAG,
+               .blk_name = "Video_DB",
+       },
+       {
+               .tag_code = VENDOR_TAG,
+               .blk_name = "Vendor_Specific_DB",
+       },
+       {
+               .tag_code = HF_VENDOR_DB_TAG,
+               .blk_name = "HF_Vendor_Specific_DB",
+       },
+       {
+               .tag_code = SPEAKER_TAG,
+               .blk_name = "Speaker_Alloc_DB",
+       },
+       {
+               .tag_code = VDTCDB_TAG,
+               .blk_name = "VESA_DTC_DB",
+       },
+       {
+               .tag_code = (USE_EXTENDED_TAG << 8) | VCDB_TAG,
+               .blk_name = "Video_Cap_DB",
+       },
+       {
+               .tag_code = (USE_EXTENDED_TAG << 8) | VSVDB_TAG,
+               .blk_name = "Vendor_Specific_Video_DB",
+       },
+       {
+               .tag_code = (USE_EXTENDED_TAG << 8) | VDDDB_TAG,
+               .blk_name = "VESA_Display_Device_DB",
+       },
+       {
+               .tag_code = (USE_EXTENDED_TAG << 8) | VVTBE_TAG,
+               .blk_name = "VESA_Video_Timing_Blk_Ext",
+       },
+       {
+               .tag_code = (USE_EXTENDED_TAG << 8) | CDB_TAG,
+               .blk_name = "Colorimetry_DB",
+       },
+       {
+               .tag_code = (USE_EXTENDED_TAG << 8) | HDR_STATIC_TAG,
+               .blk_name = "HDR_Static_Metadata",
+       },
+       {
+               .tag_code = (USE_EXTENDED_TAG << 8) | HDR_DYNAMIC_TAG,
+               .blk_name = "HDR_Dynamic_Metadata",
+       },
+       {
+               .tag_code = (USE_EXTENDED_TAG << 8) | VFPDB_TAG,
+               .blk_name = "Video_Fmt_Preference_DB",
+       },
+       {
+               .tag_code = (USE_EXTENDED_TAG << 8) | Y420VDB_TAG,
+               .blk_name = "YCbCr_420_Video_DB",
+       },
+       {
+               .tag_code = (USE_EXTENDED_TAG << 8) | Y420CMDB_TAG,
+               .blk_name = "YCbCr_420_Cap_Map_DB",
+       },
+       {
+               .tag_code = (USE_EXTENDED_TAG << 8) | VSADB_TAG,
+               .blk_name = "Vendor_Specific_Audio_DB",
+       },
+       {
+               .tag_code = (USE_EXTENDED_TAG << 8) | RCDB_TAG,
+               .blk_name = "Room_Configuration_DB",
+       },
+       {
+               .tag_code = (USE_EXTENDED_TAG << 8) | SLDB_TAG,
+               .blk_name = "Speaker_Location_DB",
+       },
+       {
+               .tag_code = (USE_EXTENDED_TAG << 8) | IFDB_TAG,
+               .blk_name = "Infoframe_DB",
+       },
+       {
+               .tag_code = TAG_MAX,
+               .blk_name = "Unrecognized_DB",
+       },
+       {},
+};
+
+char *rx_get_cta_blk_name(uint16_t tag)
+{
+       int i = 0;
+
+       for (i = 0; cta_blk[i].tag_code != TAG_MAX; i++) {
+               if (tag == cta_blk[i].tag_code)
+                       break;
+       }
+       return cta_blk[i].blk_name;
+}
+
 unsigned char rx_get_edid_index(void)
 {
        if ((edid_mode < EDID_LIST_NUM) &&
@@ -546,12 +659,25 @@ unsigned int rx_exchange_bits(unsigned int value)
 
 int rx_get_tag_code(uint8_t *edid_data)
 {
-       int tag_code;
+       int tag_code = TAG_MAX;
+       unsigned int ieee_oui;
 
-       if ((*edid_data >> 5) != 7)
+       if (!edid_data)
+               return tag_code;
+       /* extern tag */
+       if ((*edid_data >> 5) == USE_EXTENDED_TAG)
+               tag_code = (7 << 8) | *(edid_data + 1);
+       else if ((*edid_data >> 5) == VENDOR_TAG) {
+               /* diff VSDB with HF-VSDB */
+               ieee_oui = (edid_data[3] << 16) |
+                       (edid_data[2] << 8) | edid_data[1];
+               if (ieee_oui == 0x000C03)
+                       tag_code = (*edid_data >> 5);
+               else if (ieee_oui == 0xC45DD8)
+                       tag_code =
+                               (*edid_data >> 5) + HF_VSDB_OFFSET;
+       } else
                tag_code = (*edid_data >> 5);
-       else
-               tag_code = (7 << 8) | *(edid_data + 1);/*extern tag*/
 
        return tag_code;
 }
@@ -1104,23 +1230,29 @@ unsigned char rx_parse_arc_aud_type(const unsigned char *buff)
                if (!need_support_atmos_bit) {
                        need_support_atmos_bit = true;
                        hdmi_rx_top_edid_update();
-                       if (rx.open_fg) {
+                       if (rx.open_fg && (rx.port != rx.arc_port)) {
                                if (atmos_edid_update_hpd_en)
                                        rx_send_hpd_pulse();
                                rx_pr("*update edid-atmos*\n");
-                       } else
+                       } else {
                                pre_port = 0xff;
+                               rx_pr("update atmos later, in arc port:%s\n",
+                                       rx.port == rx.arc_port ? "Y" : "N");
+                       }
                }
        } else {
                if (need_support_atmos_bit) {
                        need_support_atmos_bit = false;
                        hdmi_rx_top_edid_update();
-                       if (rx.open_fg) {
+                       if (rx.open_fg && (rx.port != rx.arc_port)) {
                                if (atmos_edid_update_hpd_en)
                                        rx_send_hpd_pulse();
                                rx_pr("*update edid-no atmos*\n");
-                       } else
+                       } else {
                                pre_port = 0xff;
+                               rx_pr("update atmos later, in arc port:%s\n",
+                                       rx.port == rx.arc_port ? "Y" : "N");
+                       }
                }
        }
 
@@ -1135,12 +1267,15 @@ void rx_set_atmos_flag(bool en)
        if (need_support_atmos_bit != en) {
                need_support_atmos_bit = en;
                hdmi_rx_top_edid_update();
-               if (rx.open_fg) {
+               if (rx.open_fg && (rx.port != rx.arc_port)) {
                        if (atmos_edid_update_hpd_en)
                                rx_send_hpd_pulse();
                        rx_pr("*update edid-atmos*\n");
-               } else
+               } else {
                        pre_port = 0xff;
+                       rx_pr("update atmos later, in arc port:%s\n",
+                               rx.port == rx.arc_port ? "Y" : "N");
+               }
        }
 }
 EXPORT_SYMBOL(rx_set_atmos_flag);
@@ -1222,7 +1357,8 @@ unsigned int hdmi_rx_top_edid_update(void)
                rx_edid_update_audio_info(pedid_data,
                                rx_get_edid_size(edid_index));
        }
-
+       edid_splice_earc_capds(pedid_data,
+               recv_earc_cap_ds, earc_cap_ds_len);
        /* if (need_support_atmos_bit) */
        rx_edid_update_atmos(pedid_data);
 
@@ -1452,6 +1588,9 @@ static void get_edid_monitor_name(unsigned char *p_edid,
        unsigned char start, struct edid_info_s *edid_info)
 {
        unsigned char i, j;
+
+       if (!p_edid || !edid_info)
+               return;
        /* CEA861-F Table83 */
        for (i = 0; i < 4; i++) {
                /* 0xFC denotes that last 13 bytes of this
@@ -1541,10 +1680,12 @@ void edid_parse_block0(uint8_t *p_edid, struct edid_info_s *edid_info)
 }
 
 static void get_edid_video_data(unsigned char *buff, unsigned char start,
-       unsigned char len, struct edid_info_s *edid_info)
+       unsigned char len, struct cta_blk_parse_info *edid_info)
 {
        unsigned char i;
 
+       if (!buff || !edid_info)
+               return;
        edid_info->video_db.svd_num = len;
        for (i = 0; i < len; i++) {
                edid_info->video_db.hdmi_vic[i] =
@@ -1553,12 +1694,14 @@ static void get_edid_video_data(unsigned char *buff, unsigned char start,
 }
 
 static void get_edid_audio_data(unsigned char *buff, unsigned char start,
-       unsigned char len, struct edid_info_s *edid_info)
+       unsigned char len, struct cta_blk_parse_info *edid_info)
 {
        enum edid_audio_format_e fmt;
        int i = start;
        struct pcm_t *pcm;
 
+       if (!buff || !edid_info)
+               return;
        do {
                fmt = (buff[i] & 0x78) >> 3;/* bit6~3 */
                edid_info->audio_db.aud_fmt_sup[fmt] = 1;
@@ -1677,10 +1820,12 @@ static void get_edid_audio_data(unsigned char *buff, unsigned char start,
 }
 
 static void get_edid_speaker_data(unsigned char *buff, unsigned char start,
-       unsigned char len, struct edid_info_s *edid_info)
+       unsigned char len, struct cta_blk_parse_info *edid_info)
 {
        int i;
 
+       if (!buff || !edid_info)
+               return;
        /* speaker allocation is 3 bytes long*/
        if (len != 3) {
                rx_pr("invalid length for speaker allocation data block: %d\n",
@@ -1734,8 +1879,12 @@ static void get_edid_speaker_data(unsigned char *buff, unsigned char start,
        }
 }
 
-static void get_edid_vsdb(unsigned char *buff, unsigned char start,
-       unsigned char len, struct edid_info_s *edid_info)
+/* if is valid vsdb, then return 1
+ * if is valid hf-vsdb, then return 2
+ * if is invalid db, then return 0
+ */
+static int get_edid_vsdb(unsigned char *buff, unsigned char start,
+       unsigned char len, struct cta_blk_parse_info *edid_info)
 {
        unsigned char _3d_present_offset;
        unsigned char hdmi_vic_len;
@@ -1747,11 +1896,14 @@ static void get_edid_vsdb(unsigned char *buff, unsigned char start,
        unsigned char _3d_struct;
        unsigned char _2d_vic_order_offset;
        unsigned char temp_3d_len;
+       int ret = 0;
 
+       if (!buff || !edid_info)
+               return 0;
        /* basic 5 bytes; others: extension fields */
        if (len < 5) {
                rx_pr("invalid VSDB length: %d!\n", len);
-               return;
+               return ret;
        }
        ieee_oui = (buff[start+2] << 16) |
                (buff[start+1] << 8) |
@@ -1759,10 +1911,12 @@ static void get_edid_vsdb(unsigned char *buff, unsigned char start,
        if ((ieee_oui != 0x000C03) &&
                (ieee_oui != 0xC45DD8)) {
                rx_pr("invalid IEEE OUI\n");
-               return;
+               return ret;
        } else if (ieee_oui == 0xC45DD8) {
+               ret = 2;
                goto hf_vsdb;
        }
+       ret = 1;
        edid_info->vsdb.ieee_oui = ieee_oui;
        /* phy addr: 2 bytes*/
        edid_info->vsdb.a = (buff[start+3] >> 4) & 0xf;
@@ -1795,7 +1949,7 @@ static void get_edid_vsdb(unsigned char *buff, unsigned char start,
        if (edid_info->vsdb.latency_fields_present) {
                if (len < 10) {
                        rx_pr("invalid vsdb len for latency: %d\n", len);
-                       return;
+                       return 0;
                }
                edid_info->vsdb.video_latency = buff[start+8];
                edid_info->vsdb.audio_latency = buff[start+9];
@@ -1812,7 +1966,7 @@ static void get_edid_vsdb(unsigned char *buff, unsigned char start,
                        rx_pr("i_latency_fields should not be set\n");
                else if (len < 12) {
                        rx_pr("invalid vsdb len for i_latency: %d\n", len);
-                       return;
+                       return 0;
                }
                edid_info->vsdb.interlaced_video_latency
                        = buff[start+10];
@@ -1840,7 +1994,7 @@ static void get_edid_vsdb(unsigned char *buff, unsigned char start,
                 */
                if (len < _3d_present_offset + 2) {
                        rx_pr("invalid vsdb length for hdmi video: %d\n", len);
-                       return;
+                       return 0;
                }
                edid_info->vsdb._3d_present =
                        (buff[start+_3d_present_offset] >> 7) & 0x1;
@@ -1858,13 +2012,13 @@ static void get_edid_vsdb(unsigned char *buff, unsigned char start,
                if (hdmi_vic_len > 4) {
                        rx_pr("invalid hdmi vic len: %d\n",
                                edid_info->vsdb.hdmi_vic_len);
-                       return;
+                       return 0;
                }
 
                /* HDMI_VIC_LEN may be 0 */
                if (len < hdmi_vic_offset + hdmi_vic_len) {
                        rx_pr("invalid length for 4k2k: %d\n", len);
-                       return;
+                       return 0;
                }
                for (i = 0; i < hdmi_vic_len; i++) {
                        if (buff[start+hdmi_vic_offset+i] == 1)
@@ -1884,7 +2038,7 @@ static void get_edid_vsdb(unsigned char *buff, unsigned char start,
                /* there may be additional 0 present after 3D info  */
                if (len < _3d_struct_all_offset + hdmi_3d_len) {
                        rx_pr("invalid vsdb length for 3d: %d\n", len);
-                       return;
+                       return 0;
                }
                /* 3d_multi_present: hdmi1.4 spec page155:
                 * 0: neither structure or mask present,
@@ -1944,6 +2098,7 @@ static void get_edid_vsdb(unsigned char *buff, unsigned char start,
                                if (temp_3d_len > hdmi_3d_len) {
                                        rx_pr("invalid len for 3d_detail: %d\n",
                                                len);
+                                       ret = 0;
                                        break;
                                }
                        } else {
@@ -1952,13 +2107,14 @@ static void get_edid_vsdb(unsigned char *buff, unsigned char start,
                        }
                }
                edid_info->vsdb._2d_vic_num = j;
-               return;
+               return ret;
        }
+       return ret;
 hf_vsdb:
        /* hdmi spec2.0 Table10-6 */
        if (len < 7) {
                rx_pr("invalid HF_VSDB length: %d!\n", len);
-               return;
+               return 0;
        }
        edid_info->contain_hf_vsdb = true;
        edid_info->hf_vsdb.ieee_oui = ieee_oui;
@@ -1985,14 +2141,18 @@ hf_vsdb:
                (buff[start+6] >> 1) & 0x1;
        edid_info->hf_vsdb.dc_30bit_420 =
                buff[start+6] & 0x1;
+       return ret;
 }
 
 static void get_edid_vcdb(unsigned char *buff, unsigned char start,
-        unsigned char len, struct edid_info_s *edid_info) {
-        /* vcdb only contain 3 bytes data block. the source should
-         * ignore additional bytes (when present) and continue to
-         * parse the single byte as defined in CEA861-F Table 59.
-         */
+        unsigned char len, struct cta_blk_parse_info *edid_info)
+{
+       if (!buff || !edid_info)
+               return;
+       /* vcdb only contain 3 bytes data block. the source should
+        * ignore additional bytes (when present) and continue to
+        * parse the single byte as defined in CEA861-F Table 59.
+        */
        if (len != 2-1) {
                rx_pr("invalid length for video cap data blcok: %d!\n", len);
                /* return; */
@@ -2006,10 +2166,12 @@ static void get_edid_vcdb(unsigned char *buff, unsigned char start,
 }
 
 static void get_edid_dv_data(unsigned char *buff, unsigned char start,
-        unsigned char len, struct edid_info_s *edid_info)
+        unsigned char len, struct cta_blk_parse_info *edid_info)
 {
        unsigned int ieee_oui;
 
+       if (!buff || !edid_info)
+               return;
        if ((len != 0xE - 1) &&
                (len != 0x19 - 1)) {
                rx_pr("invalid length for dolby vision vsvdb:%d\n",
@@ -2092,7 +2254,10 @@ static void get_edid_dv_data(unsigned char *buff, unsigned char start,
 }
 
 static void get_edid_colorimetry_data(unsigned char *buff, unsigned char start,
-       unsigned char len, struct edid_info_s *edid_info) {
+       unsigned char len, struct cta_blk_parse_info *edid_info)
+{
+       if (!buff || !edid_info)
+               return;
        /* colorimetry DB only contain 3 bytes data block */
        if (len != 3-1) {
                rx_pr("invalid length for colorimetry data block:%d\n",
@@ -2116,8 +2281,10 @@ static void get_edid_colorimetry_data(unsigned char *buff, unsigned char start,
 }
 
 static void get_hdr_data(unsigned char *buff, unsigned char start,
-       unsigned char len, struct edid_info_s *edid_info)
+       unsigned char len, struct cta_blk_parse_info *edid_info)
 {
+       if (!buff || !edid_info)
+               return;
        /* Bytes 5-7 are optional to declare. 3 bytes payload at least */
        if (len < 3-1) {
                rx_pr("invalid hdr length: %d!\n", len);
@@ -2129,13 +2296,21 @@ static void get_hdr_data(unsigned char *buff, unsigned char start,
        edid_info->hdr_db.eotf_hdr = (buff[start] >> 1) & 0x1;
        edid_info->hdr_db.eotf_sdr = buff[start] & 0x1;
        edid_info->hdr_db.hdr_SMD_type1 =  buff[start+1] & 0x1;
+       if (len > 2)
+               edid_info->hdr_db.hdr_lum_max = buff[start+2];
+       if (len > 3)
+               edid_info->hdr_db.hdr_lum_avg = buff[start+3];
+       if (len > 4)
+               edid_info->hdr_db.hdr_lum_min = buff[start+4];
 }
 
 static void get_edid_y420_vid_data(unsigned char *buff, unsigned char start,
-       unsigned char len, struct edid_info_s *edid_info)
+       unsigned char len, struct cta_blk_parse_info *edid_info)
 {
        int i;
 
+       if (!buff || !edid_info)
+               return;
        if (len > 6) {
                rx_pr("y420vdb support only 4K50/60hz, smpte50/60hz, len:%d\n",
                        len);
@@ -2148,9 +2323,12 @@ static void get_edid_y420_vid_data(unsigned char *buff, unsigned char start,
 }
 
 static void get_edid_y420_cap_map_data(unsigned char *buff, unsigned char start,
-       unsigned char len, struct edid_info_s *edid_info)
+       unsigned char len, struct cta_blk_parse_info *edid_info)
 {
        unsigned int i, bit_map = 0;
+
+       if (!buff || !edid_info)
+               return;
        /* 31 SVD maxmium, 4 bytes needed */
        if (len > 4) {
                rx_pr("31 SVD maxmium, all-zero data not needed\n");
@@ -2177,93 +2355,139 @@ static void get_edid_y420_cap_map_data(unsigned char *buff, unsigned char start,
        }
 }
 
-/* parse CEA extension block */
-void edid_parse_cea_block(uint8_t *p_edid, struct edid_info_s *edid_info)
+static void get_edid_vsadb(unsigned char *buff, unsigned char start,
+       unsigned char len, struct cta_blk_parse_info *edid_info)
 {
-       /* unsigned int audio_block; */
-       unsigned int max_offset;
-       unsigned int tag_offset;
-       unsigned char tag_data;
-       unsigned char tag_code;
-       unsigned char extend_tag_code;
-       unsigned char data_blk_len;
+       int i;
 
-       if (!p_edid || !edid_info)
+       if (!buff || !edid_info)
                return;
-       if (p_edid[0] != 0x02) {
-               rx_pr("not a valid CEA block!\n");
+       if (len > 27-2) {
+               /* CTA-861-G 7.5.8 */
+               rx_pr("over VSADB max size(27 bytes), len:%d\n", len);
+               return;
+       } else if (len < 3) {
+               rx_pr("no valid IEEE OUI, len:%d\n", len);
                return;
        }
-       edid_info->cea_tag = p_edid[0];
-       edid_info->cea_revision = p_edid[1];
-       max_offset = p_edid[2];
-       edid_info->dtd_offset = max_offset;
-       edid_info->underscan_sup = (p_edid[3] >> 7) & 0x1;
-       edid_info->basic_aud_sup = (p_edid[3] >> 6) & 0x1;
-       edid_info->ycc444_sup = (p_edid[3] >> 5) & 0x1;
-       edid_info->ycc422_sup = (p_edid[3] >> 4) & 0x1;
-       edid_info->native_dtd_num = p_edid[3] & 0xF;
+       edid_info->contain_vsadb = true;
+       edid_info->vsadb_ieee =
+               buff[start] |
+               (buff[start+1] << 8) |
+               (buff[start+2] << 16);
+       for (i = 0; i < len-3; i++)
+               edid_info->vsadb_payload[i] = buff[start+3+i];
+}
 
-       tag_offset = 4;/* block offset */
-       do {
-               tag_data = p_edid[tag_offset];
+static void get_edid_rcdb(unsigned char *buff, unsigned char start,
+       unsigned char len, struct cta_blk_parse_info *edid_info)
+{
+}
+
+static void get_edid_sldb(unsigned char *buff, unsigned char start,
+       unsigned char len, struct cta_blk_parse_info *edid_info)
+{
+}
+
+/* parse multi block data buff */
+void parse_cta_data_block(uint8_t *p_blk_buff, uint8_t buf_len,
+       struct cta_blk_parse_info *blk_parse_info)
+{
+       unsigned char tag_data, tag_code, extend_tag_code;
+       unsigned char data_blk_len;
+       unsigned char index = 0;
+       unsigned char i = 0;
+       int ret;
+
+       if (!p_blk_buff || !blk_parse_info || (buf_len == 0))
+               return;
+
+       while ((index < buf_len) && (i < DATA_BLK_MAX_NUM)) {
+               tag_data = p_blk_buff[index];
                tag_code = (tag_data & 0xE0) >> 5;
-               /* data block playload length */
+               /* data block payload length */
                data_blk_len = tag_data & 0x1F;
                /* length beyond max offset, force to break */
-               if ((tag_offset + data_blk_len) >= max_offset)
+               if ((index + data_blk_len + 1) > buf_len) {
+                       rx_pr("unexpected data blk len\n");
                        break;
+               }
+               blk_parse_info->db_info[i].cta_blk_index = i;
+               blk_parse_info->db_info[i].tag_code = tag_code;
+               blk_parse_info->db_info[i].offset = index;
+               /* length including header */
+               blk_parse_info->db_info[i].blk_len = data_blk_len+1;
+               blk_parse_info->data_blk_num = i+1;
                switch (tag_code) {
-               /* data block playload offset: tag_offset+1
+               /* data block payload offset: index+1
                 * length: payload length
                 */
                case VIDEO_TAG:
-                       get_edid_video_data(p_edid, tag_offset+1,
-                               data_blk_len, edid_info);
+                       get_edid_video_data(p_blk_buff, index+1,
+                               data_blk_len, blk_parse_info);
                        break;
                case AUDIO_TAG:
-                       get_edid_audio_data(p_edid, tag_offset+1,
-                               data_blk_len, edid_info);
+                       get_edid_audio_data(p_blk_buff, index+1,
+                               data_blk_len, blk_parse_info);
                        break;
                case SPEAKER_TAG:
-                       get_edid_speaker_data(p_edid, tag_offset+1,
-                               data_blk_len, edid_info);
+                       get_edid_speaker_data(p_blk_buff, index+1,
+                               data_blk_len, blk_parse_info);
                        break;
                case VENDOR_TAG:
-                       get_edid_vsdb(p_edid, tag_offset+1,
-                               data_blk_len, edid_info);
+                       ret = get_edid_vsdb(p_blk_buff, index+1,
+                               data_blk_len, blk_parse_info);
+                       if (ret == 2)
+                               blk_parse_info->db_info[i].tag_code =
+                                       tag_code + HF_VSDB_OFFSET;
+                       else if (ret == 0)
+                               rx_pr("illegal VSDB\n");
                        break;
-               case VESA_TAG:
+               case VDTCDB_TAG:
                        break;
                case USE_EXTENDED_TAG:
-                       extend_tag_code = p_edid[tag_offset+1];
+                       extend_tag_code = p_blk_buff[index+1];
+                       blk_parse_info->db_info[i].tag_code =
+                               (USE_EXTENDED_TAG << 8) | extend_tag_code;
                        switch (extend_tag_code) {
                        /* offset: start after extended tag code
                         * length: payload length except extend tag
                         */
                        case VCDB_TAG:
-                               get_edid_vcdb(p_edid, tag_offset+2,
-                                       data_blk_len-1, edid_info);
+                               get_edid_vcdb(p_blk_buff, index+2,
+                                       data_blk_len-1, blk_parse_info);
                                break;
                        case VSVDB_TAG:
-                               get_edid_dv_data(p_edid, tag_offset+2,
-                                       data_blk_len-1, edid_info);
+                               get_edid_dv_data(p_blk_buff, index+2,
+                                       data_blk_len-1, blk_parse_info);
                                break;
                        case CDB_TAG:
-                               get_edid_colorimetry_data(p_edid, tag_offset+2,
-                                       data_blk_len-1, edid_info);
+                               get_edid_colorimetry_data(p_blk_buff, index+2,
+                                       data_blk_len-1, blk_parse_info);
                                break;
-                       case HDR_TAG:
-                               get_hdr_data(p_edid, tag_offset+2,
-                                       data_blk_len-1, edid_info);
+                       case HDR_STATIC_TAG:
+                               get_hdr_data(p_blk_buff, index+2,
+                                       data_blk_len-1, blk_parse_info);
                                break;
                        case Y420VDB_TAG:
-                               get_edid_y420_vid_data(p_edid, tag_offset+2,
-                                       data_blk_len-1, edid_info);
+                               get_edid_y420_vid_data(p_blk_buff, index+2,
+                                       data_blk_len-1, blk_parse_info);
                                break;
                        case Y420CMDB_TAG:
-                               get_edid_y420_cap_map_data(p_edid, tag_offset+2,
-                                       data_blk_len-1, edid_info);
+                               get_edid_y420_cap_map_data(p_blk_buff, index+2,
+                                       data_blk_len-1, blk_parse_info);
+                               break;
+                       case VSADB_TAG:
+                               get_edid_vsadb(p_blk_buff, index+2,
+                                       data_blk_len-1, blk_parse_info);
+                               break;
+                       case RCDB_TAG:
+                               get_edid_rcdb(p_blk_buff, index+2,
+                                       data_blk_len-1, blk_parse_info);
+                               break;
+                       case SLDB_TAG:
+                               get_edid_sldb(p_blk_buff, index+2,
+                                       data_blk_len-1, blk_parse_info);
                                break;
                        default:
                                break;
@@ -2273,21 +2497,63 @@ void edid_parse_cea_block(uint8_t *p_edid, struct edid_info_s *edid_info)
                        break;
                }
                /* next tag offset */
-               tag_offset += ((tag_data & 0x1F)+1);
-       } while (tag_offset < max_offset);
+               index += (data_blk_len+1);
+               i++;
+       }
 }
 
-void rx_edid_parse_print(struct edid_info_s *edid_info)
+/* parse CEA extension block */
+void edid_parse_cea_ext_block(uint8_t *p_edid,
+       struct cea_ext_parse_info *edid_info)
 {
+       unsigned int max_offset;
+       unsigned int blk_start_offset;
+       unsigned char data_blk_total_len;
        unsigned char i;
-       unsigned char hdmi_vic;
-       enum edid_audio_format_e fmt;
-       union bit_rate_u *bit_rate;
-       unsigned char svd_num;
-       unsigned char _2d_vic_order;
-       unsigned char _3d_struct;
-       unsigned char _3d_detail;
 
+       if (!p_edid || !edid_info)
+               return;
+       if (p_edid[0] != 0x02) {
+               rx_pr("not a valid CEA block!\n");
+               return;
+       }
+       edid_info->cea_tag = p_edid[0];
+       edid_info->cea_revision = p_edid[1];
+       max_offset = p_edid[2];
+       edid_info->dtd_offset = max_offset;
+       edid_info->underscan_sup = (p_edid[3] >> 7) & 0x1;
+       edid_info->basic_aud_sup = (p_edid[3] >> 6) & 0x1;
+       edid_info->ycc444_sup = (p_edid[3] >> 5) & 0x1;
+       edid_info->ycc422_sup = (p_edid[3] >> 4) & 0x1;
+       edid_info->native_dtd_num = p_edid[3] & 0xF;
+
+       blk_start_offset = 4;
+       data_blk_total_len = max_offset - blk_start_offset;
+       parse_cta_data_block(&p_edid[blk_start_offset],
+               data_blk_total_len, &edid_info->blk_parse_info);
+
+       for (i = 0; i < edid_info->blk_parse_info.data_blk_num; i++)
+               edid_info->blk_parse_info.db_info[i].offset += blk_start_offset;
+}
+
+void rx_edid_parse(uint8_t *p_edid, struct edid_info_s *edid_info)
+{
+       if (!p_edid || !edid_info)
+               return;
+       edid_parse_block0(p_edid, edid_info);
+       edid_parse_cea_ext_block(p_edid+EDID_EXT_BLK_OFF,
+               &edid_info->cea_ext_info);
+
+       edid_info->free_size =
+               rx_edid_free_size(p_edid, EDID_SIZE);
+       edid_info->total_free_size =
+               rx_edid_total_free_size(p_edid, EDID_SIZE);
+       edid_info->dtd_size =
+               rx_get_cea_dtd_size(p_edid, EDID_SIZE);
+}
+
+void rx_parse_blk0_print(struct edid_info_s *edid_info)
+{
        if (!edid_info)
                return;
        rx_pr("****EDID Basic Block****\n");
@@ -2305,43 +2571,51 @@ void rx_edid_parse_print(struct edid_info_s *edid_info)
                edid_info->max_sup_pixel_clk);
        rx_pr("extension_flag: %d\n", edid_info->extension_flag);
        rx_pr("block0_chk_sum: 0x%x\n", edid_info->block0_chk_sum);
+}
 
-       rx_pr("****CEA block header****\n");
-       rx_pr("underscan_sup: %d\n", edid_info->underscan_sup);
-       rx_pr("basic_aud_sup: %d\n", edid_info->basic_aud_sup);
-       rx_pr("ycc444_sup: %d\n", edid_info->ycc444_sup);
-       rx_pr("ycc422_sup: %d\n", edid_info->ycc422_sup);
-       rx_pr("native_dtd_num: %d\n", edid_info->native_dtd_num);
+void rx_parse_print_vdb(struct video_db_s *video_db)
+{
+       unsigned char i;
+       unsigned char hdmi_vic;
 
+       if (!video_db)
+               return;
        rx_pr("****Video Data Block****\n");
        rx_pr("support SVD list:\n");
-       svd_num = edid_info->video_db.svd_num;
-       for (i = 0; i < edid_info->video_db.svd_num; i++) {
-               hdmi_vic = edid_info->video_db.hdmi_vic[i];
+       for (i = 0; i < video_db->svd_num; i++) {
+               hdmi_vic = video_db->hdmi_vic[i];
                rx_edid_print_vic_fmt(i, hdmi_vic);
        }
+}
 
+void rx_parse_print_adb(struct audio_db_s *audio_db)
+{
+       enum edid_audio_format_e fmt;
+       union bit_rate_u *bit_rate;
+
+       if (!audio_db)
+               return;
        rx_pr("****Audio Data Block****\n");
        for (fmt = AUDIO_FORMAT_LPCM; fmt <= AUDIO_FORMAT_WMAPRO; fmt++) {
-               if (edid_info->audio_db.aud_fmt_sup[fmt]) {
+               if (audio_db->aud_fmt_sup[fmt]) {
                        rx_pr("audio fmt: %s\n", aud_fmt[fmt]);
                        rx_pr("\tmax channel: %d\n",
-                               edid_info->audio_db.sad[fmt].max_channel+1);
-                       if (edid_info->audio_db.sad[fmt].freq_192khz)
+                               audio_db->sad[fmt].max_channel+1);
+                       if (audio_db->sad[fmt].freq_192khz)
                                rx_pr("\tfreq_192khz\n");
-                       if (edid_info->audio_db.sad[fmt].freq_176_4khz)
+                       if (audio_db->sad[fmt].freq_176_4khz)
                                rx_pr("\tfreq_176.4khz\n");
-                       if (edid_info->audio_db.sad[fmt].freq_96khz)
+                       if (audio_db->sad[fmt].freq_96khz)
                                rx_pr("\tfreq_96khz\n");
-                       if (edid_info->audio_db.sad[fmt].freq_88_2khz)
+                       if (audio_db->sad[fmt].freq_88_2khz)
                                rx_pr("\tfreq_88.2khz\n");
-                       if (edid_info->audio_db.sad[fmt].freq_48khz)
+                       if (audio_db->sad[fmt].freq_48khz)
                                rx_pr("\tfreq_48khz\n");
-                       if (edid_info->audio_db.sad[fmt].freq_44_1khz)
+                       if (audio_db->sad[fmt].freq_44_1khz)
                                rx_pr("\tfreq_44.1khz\n");
-                       if (edid_info->audio_db.sad[fmt].freq_32khz)
+                       if (audio_db->sad[fmt].freq_32khz)
                                rx_pr("\tfreq_32khz\n");
-                       bit_rate = &(edid_info->audio_db.sad[fmt].bit_rate);
+                       bit_rate = &(audio_db->sad[fmt].bit_rate);
                        if (fmt == AUDIO_FORMAT_LPCM) {
                                rx_pr("sample size:\n");
                                if (bit_rate->pcm.size_16bit)
@@ -2360,31 +2634,51 @@ void rx_edid_parse_print(struct edid_info_s *edid_info)
                        }
                }
        }
+}
 
+/* may need extend spker alloc */
+void rx_parse_print_spk_alloc(struct speaker_alloc_db_s *spk_alloc)
+{
+       if (!spk_alloc)
+               return;
        rx_pr("****Speaker Allocation Data Block****\n");
-       if (edid_info->speaker_alloc.flw_frw)
+       if (spk_alloc->flw_frw)
                rx_pr("FLW/FRW\n");
-       if (edid_info->speaker_alloc.rlc_rrc)
+       if (spk_alloc->rlc_rrc)
                rx_pr("RLC/RRC\n");
-       if (edid_info->speaker_alloc.flc_frc)
+       if (spk_alloc->flc_frc)
                rx_pr("FLC/FRC\n");
-       if (edid_info->speaker_alloc.rc)
+       if (spk_alloc->rc)
                rx_pr("RC\n");
-       if (edid_info->speaker_alloc.rl_rr)
+       if (spk_alloc->rl_rr)
                rx_pr("RL/RR\n");
-       if (edid_info->speaker_alloc.fc)
+       if (spk_alloc->fc)
                rx_pr("FC\n");
-       if (edid_info->speaker_alloc.lfe)
+       if (spk_alloc->lfe)
                rx_pr("LFE\n");
-       if (edid_info->speaker_alloc.fl_fr)
+       if (spk_alloc->fl_fr)
                rx_pr("FL/FR\n");
-       if (edid_info->speaker_alloc.fch)
+       if (spk_alloc->fch)
                rx_pr("FCH\n");
-       if (edid_info->speaker_alloc.tc)
+       if (spk_alloc->tc)
                rx_pr("TC\n");
-       if (edid_info->speaker_alloc.flh_frh)
+       if (spk_alloc->flh_frh)
                rx_pr("FLH_FRH\n");
+}
+
+void rx_parse_print_vsdb(struct cta_blk_parse_info *edid_info)
+{
+       unsigned char i;
+       unsigned char hdmi_vic;
+       unsigned char svd_num;
+       unsigned char _2d_vic_order;
+       unsigned char _3d_struct;
+       unsigned char _3d_detail;
+
+       if (!edid_info)
+               return;
 
+       svd_num = edid_info->video_db.svd_num;
        rx_pr("****Vender Specific Data Block****\n");
        rx_pr("IEEE OUI: %06X\n",
                edid_info->vsdb.ieee_oui);
@@ -2500,208 +2794,314 @@ void rx_edid_parse_print(struct edid_info_s *edid_info)
                                _3d_detail_x[_3d_detail]);
                }
        }
+}
 
-       if (edid_info->contain_hf_vsdb) {
-               rx_pr("****HF-VSDB****\n");
-               rx_pr("IEEE OUI: %06X\n",
-                       edid_info->hf_vsdb.ieee_oui);
-               rx_pr("hf-vsdb version: %d\n",
-                       edid_info->hf_vsdb.version);
-               rx_pr("max_tmds_rate: %dMHz\n",
-                       edid_info->hf_vsdb.max_tmds_rate*5);
-               rx_pr("scdc_present: %d\n",
-                       edid_info->hf_vsdb.scdc_present);
-               rx_pr("rr_cap: %d\n",
-                       edid_info->hf_vsdb.rr_cap);
-               rx_pr("lte_340m_scramble: %d\n",
-                       edid_info->hf_vsdb.lte_340m_scramble);
-               rx_pr("independ_view: %d\n",
-                       edid_info->hf_vsdb.independ_view);
-               rx_pr("dual_view: %d\n",
-                       edid_info->hf_vsdb.dual_view);
-               rx_pr("_3d_osd_disparity: %d\n",
-                       edid_info->hf_vsdb._3d_osd_disparity);
-
-               rx_pr("48bit 420 endode: %d\n",
-                       edid_info->hf_vsdb.dc_48bit_420);
-               rx_pr("36bit 420 endode: %d\n",
-                       edid_info->hf_vsdb.dc_36bit_420);
-               rx_pr("30bit 420 endode: %d\n",
-                       edid_info->hf_vsdb.dc_30bit_420);
-       }
-
-       if (edid_info->contain_vcdb) {
-               rx_pr("****Video Cap Data Block****\n");
-               rx_pr("YCC Quant Range:\n");
-               if (edid_info->vcdb.quanti_range_ycc)
-                       rx_pr("\tSelectable(via AVI YQ)\n");
-               else
-                       rx_pr("\tNo Data\n");
+void rx_parse_print_hf_vsdb(struct hf_vsdb_s *hf_vsdb)
+{
+       if (!hf_vsdb)
+               return;
+       rx_pr("****HF-VSDB****\n");
+       rx_pr("IEEE OUI: %06X\n",
+               hf_vsdb->ieee_oui);
+       rx_pr("hf-vsdb version: %d\n",
+               hf_vsdb->version);
+       rx_pr("max_tmds_rate: %dMHz\n",
+               hf_vsdb->max_tmds_rate*5);
+       rx_pr("scdc_present: %d\n",
+               hf_vsdb->scdc_present);
+       rx_pr("rr_cap: %d\n",
+               hf_vsdb->rr_cap);
+       rx_pr("lte_340m_scramble: %d\n",
+               hf_vsdb->lte_340m_scramble);
+       rx_pr("independ_view: %d\n",
+               hf_vsdb->independ_view);
+       rx_pr("dual_view: %d\n",
+               hf_vsdb->dual_view);
+       rx_pr("_3d_osd_disparity: %d\n",
+               hf_vsdb->_3d_osd_disparity);
+       rx_pr("48bit 420 endode: %d\n",
+               hf_vsdb->dc_48bit_420);
+       rx_pr("36bit 420 endode: %d\n",
+               hf_vsdb->dc_36bit_420);
+       rx_pr("30bit 420 endode: %d\n",
+               hf_vsdb->dc_30bit_420);
+}
 
-               rx_pr("RGB Quant Range:\n");
-               if (edid_info->vcdb.quanti_range_rgb)
-                       rx_pr("\tSelectable(via AVI Q)\n");
-               else
-                       rx_pr("\tNo Data\n");
+void rx_parse_print_vcdb(struct video_cap_db_s *vcdb)
+{
+       if (!vcdb)
+               return;
+       rx_pr("****Video Cap Data Block****\n");
+       rx_pr("YCC Quant Range:\n");
+       if (vcdb->quanti_range_ycc)
+               rx_pr("\tSelectable(via AVI YQ)\n");
+       else
+               rx_pr("\tNo Data\n");
 
-               rx_pr("PT Scan behavior:\n");
-               switch (edid_info->vcdb.s_PT) {
-               case 0:
-                       rx_pr("\trefer to CE/IT fields\n");
-                       break;
-               case 1:
-                       rx_pr("\tAlways Overscanned\n");
-                       break;
-               case 2:
-                       rx_pr("\tAlways Underscanned\n");
-                       break;
-               case 3:
-                       rx_pr("\tSupport both over and underscan\n");
-                       break;
-               default:
-                       break;
-               }
-               rx_pr("IT Scan behavior:\n");
-               switch (edid_info->vcdb.s_IT) {
-               case 0:
-                       rx_pr("\tIT video format not support\n");
-                       break;
-               case 1:
-                       rx_pr("\tAlways Overscanned\n");
-                       break;
-               case 2:
-                       rx_pr("\tAlways Underscanned\n");
-                       break;
-               case 3:
-                       rx_pr("\tSupport both over and underscan\n");
-                       break;
-               default:
-                       break;
-               }
-               rx_pr("CE Scan behavior:\n");
-               switch (edid_info->vcdb.s_CE) {
-               case 0:
-                       rx_pr("\tCE video format not support\n");
-                       break;
-               case 1:
-                       rx_pr("\tAlways Overscanned\n");
-                       break;
-               case 2:
-                       rx_pr("\tAlways Underscanned\n");
-                       break;
-               case 3:
-                       rx_pr("\tSupport both over and underscan\n");
-                       break;
-               default:
-                       break;
-               }
+       rx_pr("RGB Quant Range:\n");
+       if (vcdb->quanti_range_rgb)
+               rx_pr("\tSelectable(via AVI Q)\n");
+       else
+               rx_pr("\tNo Data\n");
+
+       rx_pr("PT Scan behavior:\n");
+       switch (vcdb->s_PT) {
+       case 0:
+               rx_pr("\trefer to CE/IT fields\n");
+               break;
+       case 1:
+               rx_pr("\tAlways Overscanned\n");
+               break;
+       case 2:
+               rx_pr("\tAlways Underscanned\n");
+               break;
+       case 3:
+               rx_pr("\tSupport both over and underscan\n");
+               break;
+       default:
+               break;
+       }
+       rx_pr("IT Scan behavior:\n");
+       switch (vcdb->s_IT) {
+       case 0:
+               rx_pr("\tIT video format not support\n");
+               break;
+       case 1:
+               rx_pr("\tAlways Overscanned\n");
+               break;
+       case 2:
+               rx_pr("\tAlways Underscanned\n");
+               break;
+       case 3:
+               rx_pr("\tSupport both over and underscan\n");
+               break;
+       default:
+               break;
+       }
+       rx_pr("CE Scan behavior:\n");
+       switch (vcdb->s_CE) {
+       case 0:
+               rx_pr("\tCE video format not support\n");
+               break;
+       case 1:
+               rx_pr("\tAlways Overscanned\n");
+               break;
+       case 2:
+               rx_pr("\tAlways Underscanned\n");
+               break;
+       case 3:
+               rx_pr("\tSupport both over and underscan\n");
+               break;
+       default:
+               break;
        }
+}
 
-       if (edid_info->contain_vsvdb) {
-               rx_pr("****VSVDB(dolby vision)****\n");
-               rx_pr("IEEE_OUI: %06X\n",
-                       edid_info->dv_vsvdb.ieee_oui);
-               rx_pr("vsvdb version: %d\n",
-                       edid_info->dv_vsvdb.version);
-               rx_pr("sup_global_dimming: %d\n",
-                       edid_info->dv_vsvdb.sup_global_dimming);
-               rx_pr("sup_2160p60hz: %d\n",
-                       edid_info->dv_vsvdb.sup_2160p60hz);
-               rx_pr("sup_yuv422_12bit: %d\n",
-                       edid_info->dv_vsvdb.sup_yuv422_12bit);
-               rx_pr("Rx: 0x%x\n", edid_info->dv_vsvdb.Rx);
-               rx_pr("Ry: 0x%x\n", edid_info->dv_vsvdb.Ry);
-               rx_pr("Gx: 0x%x\n", edid_info->dv_vsvdb.Gx);
-               rx_pr("Gy: 0x%x\n", edid_info->dv_vsvdb.Gy);
-               rx_pr("Bx: 0x%x\n", edid_info->dv_vsvdb.Bx);
-               rx_pr("By: 0x%x\n", edid_info->dv_vsvdb.By);
-               if (edid_info->dv_vsvdb.version == 0) {
-                       rx_pr("target max pq: 0x%x\n",
-                               edid_info->dv_vsvdb.tmaxPQ);
-                       rx_pr("target min pq: 0x%x\n",
-                               edid_info->dv_vsvdb.tminPQ);
-                       rx_pr("dm_major_ver: 0x%x\n",
-                               edid_info->dv_vsvdb.dm_major_ver);
-                       rx_pr("dm_minor_ver: 0x%x\n",
-                               edid_info->dv_vsvdb.dm_minor_ver);
-               } else if (edid_info->dv_vsvdb.version == 1) {
-                       rx_pr("DM_version: 0x%x\n",
-                               edid_info->dv_vsvdb.DM_version);
-                       rx_pr("target_max_lum: 0x%x\n",
-                               edid_info->dv_vsvdb.target_max_lum);
-                       rx_pr("target_min_lum: 0x%x\n",
-                               edid_info->dv_vsvdb.target_min_lum);
-                       rx_pr("colormetry: 0x%x\n",
-                               edid_info->dv_vsvdb.colormetry);
-               }
+void rx_parse_print_vsvdb(struct dv_vsvdb_s *dv_vsvdb)
+{
+       if (!dv_vsvdb)
+               return;
+       rx_pr("****VSVDB(dolby vision)****\n");
+       rx_pr("IEEE_OUI: %06X\n",
+               dv_vsvdb->ieee_oui);
+       rx_pr("vsvdb version: %d\n",
+               dv_vsvdb->version);
+       rx_pr("sup_global_dimming: %d\n",
+               dv_vsvdb->sup_global_dimming);
+       rx_pr("sup_2160p60hz: %d\n",
+               dv_vsvdb->sup_2160p60hz);
+       rx_pr("sup_yuv422_12bit: %d\n",
+               dv_vsvdb->sup_yuv422_12bit);
+       rx_pr("Rx: 0x%x\n", dv_vsvdb->Rx);
+       rx_pr("Ry: 0x%x\n", dv_vsvdb->Ry);
+       rx_pr("Gx: 0x%x\n", dv_vsvdb->Gx);
+       rx_pr("Gy: 0x%x\n", dv_vsvdb->Gy);
+       rx_pr("Bx: 0x%x\n", dv_vsvdb->Bx);
+       rx_pr("By: 0x%x\n", dv_vsvdb->By);
+       if (dv_vsvdb->version == 0) {
+               rx_pr("target max pq: 0x%x\n",
+                       dv_vsvdb->tmaxPQ);
+               rx_pr("target min pq: 0x%x\n",
+                       dv_vsvdb->tminPQ);
+               rx_pr("dm_major_ver: 0x%x\n",
+                       dv_vsvdb->dm_major_ver);
+               rx_pr("dm_minor_ver: 0x%x\n",
+                       dv_vsvdb->dm_minor_ver);
+       } else if (dv_vsvdb->version == 1) {
+               rx_pr("DM_version: 0x%x\n",
+                       dv_vsvdb->DM_version);
+               rx_pr("target_max_lum: 0x%x\n",
+                       dv_vsvdb->target_max_lum);
+               rx_pr("target_min_lum: 0x%x\n",
+                       dv_vsvdb->target_min_lum);
+               rx_pr("colormetry: 0x%x\n",
+                       dv_vsvdb->colormetry);
        }
+}
+void rx_parse_print_cdb(struct colorimetry_db_s *color_db)
+{
+       if (!color_db)
+               return;
+       rx_pr("****Colorimetry Data Block****\n");
+       rx_pr("supported colorimetry:\n");
+       if (color_db->BT2020_RGB)
+               rx_pr("\tBT2020_RGB\n");
+       if (color_db->BT2020_YCC)
+               rx_pr("\tBT2020_YCC\n");
+       if (color_db->BT2020_cYCC)
+               rx_pr("\tBT2020_cYCC\n");
+       if (color_db->Adobe_RGB)
+               rx_pr("\tAdobe_RGB\n");
+       if (color_db->Adobe_YCC601)
+               rx_pr("\tAdobe_YCC601\n");
+       if (color_db->sYCC601)
+               rx_pr("\tsYCC601\n");
+       if (color_db->xvYCC709)
+               rx_pr("\txvYCC709\n");
+       if (color_db->xvYCC601)
+               rx_pr("\txvYCC601\n");
+
+       rx_pr("supported colorimetry metadata:\n");
+       if (color_db->MD3)
+               rx_pr("\tMD3\n");
+       if (color_db->MD2)
+               rx_pr("\tMD2\n");
+       if (color_db->MD1)
+               rx_pr("\tMD1\n");
+       if (color_db->MD0)
+               rx_pr("\tMD0\n");
+}
 
-       if (edid_info->contain_cdb) {
-               rx_pr("****Colorimetry Data Block****\n");
-               rx_pr("supported colorimetry:\n");
-               if (edid_info->color_db.BT2020_RGB)
-                       rx_pr("\tBT2020_RGB\n");
-               if (edid_info->color_db.BT2020_YCC)
-                       rx_pr("\tBT2020_YCC\n");
-               if (edid_info->color_db.BT2020_cYCC)
-                       rx_pr("\tBT2020_cYCC\n");
-               if (edid_info->color_db.Adobe_RGB)
-                       rx_pr("\tAdobe_RGB\n");
-               if (edid_info->color_db.Adobe_YCC601)
-                       rx_pr("\tAdobe_YCC601\n");
-               if (edid_info->color_db.sYCC601)
-                       rx_pr("\tsYCC601\n");
-               if (edid_info->color_db.xvYCC709)
-                       rx_pr("\txvYCC709\n");
-               if (edid_info->color_db.xvYCC601)
-                       rx_pr("\txvYCC601\n");
-
-               rx_pr("supported colorimetry metadata:\n");
-               if (edid_info->color_db.MD3)
-                       rx_pr("\tMD3\n");
-               if (edid_info->color_db.MD2)
-                       rx_pr("\tMD2\n");
-               if (edid_info->color_db.MD1)
-                       rx_pr("\tMD1\n");
-               if (edid_info->color_db.MD0)
-                       rx_pr("\tMD0\n");
-       }
-
-       if (edid_info->contain_hdr_db) {
-               rx_pr("****HDR Static Metadata Data Block****\n");
-               rx_pr("eotf_hlg: %d\n",
-                       edid_info->hdr_db.eotf_hlg);
-               rx_pr("eotf_smpte_st_2084: %d\n",
-                       edid_info->hdr_db.eotf_smpte_st_2084);
-               rx_pr("eotf_hdr: %d\n",
-                       edid_info->hdr_db.eotf_hdr);
-               rx_pr("eotf_sdr: %d\n",
-                       edid_info->hdr_db.eotf_sdr);
-               rx_pr("hdr_SMD_type1: %d\n",
-                       edid_info->hdr_db.hdr_SMD_type1);
-       }
-
-       if (edid_info->contain_y420_vdb) {
-               rx_pr("****Y420 Video Data Block****\n");
-               for (i = 0; i < edid_info->y420_vic_len; i++)
-                       rx_edid_print_vic_fmt(i,
-                               edid_info->y420_vdb_vic[i]);
-       }
-
-       if (edid_info->contain_y420_cmdb) {
-               rx_pr("****Yc420 capability map****\n");
-               if (edid_info->y420_all_vic)
-                       rx_pr("all vic support y420\n");
-               else {
-                       for (i = 0; i < 31; i++) {
-                               hdmi_vic = edid_info->y420_cmdb_vic[i];
-                               if (hdmi_vic)
-                                       rx_edid_print_vic_fmt(i, hdmi_vic);
-                       }
+void rx_parse_print_hdr_static(struct hdr_db_s *hdr_db)
+{
+       if (!hdr_db)
+               return;
+       rx_pr("****HDR Static Metadata Data Block****\n");
+       rx_pr("eotf_hlg: %d\n",
+               hdr_db->eotf_hlg);
+       rx_pr("eotf_smpte_st_2084: %d\n",
+               hdr_db->eotf_smpte_st_2084);
+       rx_pr("eotf_hdr: %d\n",
+               hdr_db->eotf_hdr);
+       rx_pr("eotf_sdr: %d\n",
+               hdr_db->eotf_sdr);
+       rx_pr("hdr_SMD_type1: %d\n",
+               hdr_db->hdr_SMD_type1);
+       if (hdr_db->hdr_lum_max)
+               rx_pr("Desired Content Max Luminance: 0x%x\n",
+                       hdr_db->hdr_lum_max);
+       if (hdr_db->hdr_lum_avg)
+               rx_pr("Desired Content Max Frame-avg Luminance: 0x%x\n",
+                       hdr_db->hdr_lum_avg);
+       if (hdr_db->hdr_lum_min)
+               rx_pr("Desired Content Min Luminance: 0x%x\n",
+                       hdr_db->hdr_lum_min);
+}
+
+void rx_parse_print_y420vdb(struct cta_blk_parse_info *edid_info)
+{
+       unsigned char i;
+
+       if (!edid_info)
+               return;
+       rx_pr("****Y420 Video Data Block****\n");
+       for (i = 0; i < edid_info->y420_vic_len; i++)
+               rx_edid_print_vic_fmt(i,
+                       edid_info->y420_vdb_vic[i]);
+}
+
+void rx_parse_print_y420cmdb(struct cta_blk_parse_info *edid_info)
+{
+       unsigned char i;
+       unsigned char hdmi_vic;
+
+       if (!edid_info)
+               return;
+       rx_pr("****Yc420 capability map Data Block****\n");
+       if (edid_info->y420_all_vic)
+               rx_pr("all vic support y420\n");
+       else {
+               for (i = 0; i < 31; i++) {
+                       hdmi_vic = edid_info->y420_cmdb_vic[i];
+                       if (hdmi_vic)
+                               rx_edid_print_vic_fmt(i, hdmi_vic);
                }
        }
 }
 
+void rx_cea_ext_parse_print(struct cea_ext_parse_info *cea_ext_info)
+{
+       if (!cea_ext_info)
+               return;
+       rx_pr("****CEA Extension Block Header****\n");
+       rx_pr("cea_tag: 0x%x\n", cea_ext_info->cea_tag);
+       rx_pr("cea_revision: 0x%x\n", cea_ext_info->cea_revision);
+       rx_pr("dtd offset: %d\n", cea_ext_info->dtd_offset);
+       rx_pr("underscan_sup: %d\n", cea_ext_info->underscan_sup);
+       rx_pr("basic_aud_sup: %d\n", cea_ext_info->basic_aud_sup);
+       rx_pr("ycc444_sup: %d\n", cea_ext_info->ycc444_sup);
+       rx_pr("ycc422_sup: %d\n", cea_ext_info->ycc422_sup);
+       rx_pr("native_dtd_num: %d\n", cea_ext_info->native_dtd_num);
+
+       rx_parse_print_vdb(&cea_ext_info->blk_parse_info.video_db);
+       rx_parse_print_adb(&cea_ext_info->blk_parse_info.audio_db);
+       rx_parse_print_spk_alloc(&cea_ext_info->blk_parse_info.speaker_alloc);
+       rx_parse_print_vsdb(&cea_ext_info->blk_parse_info);
+       if (cea_ext_info->blk_parse_info.contain_hf_vsdb)
+               rx_parse_print_hf_vsdb(&cea_ext_info->blk_parse_info.hf_vsdb);
+       if (cea_ext_info->blk_parse_info.contain_vcdb)
+               rx_parse_print_vcdb(&cea_ext_info->blk_parse_info.vcdb);
+       if (cea_ext_info->blk_parse_info.contain_cdb)
+               rx_parse_print_cdb(&cea_ext_info->blk_parse_info.color_db);
+       if (cea_ext_info->blk_parse_info.contain_vsvdb)
+               rx_parse_print_vsvdb(&cea_ext_info->blk_parse_info.dv_vsvdb);
+       if (cea_ext_info->blk_parse_info.contain_hdr_db)
+               rx_parse_print_hdr_static(&cea_ext_info->blk_parse_info.hdr_db);
+       if (cea_ext_info->blk_parse_info.contain_y420_vdb)
+               rx_parse_print_y420vdb(&cea_ext_info->blk_parse_info);
+       if (cea_ext_info->blk_parse_info.contain_y420_cmdb)
+               rx_parse_print_y420cmdb(&cea_ext_info->blk_parse_info);
+}
+
+void rx_edid_parse_print(struct edid_info_s *edid_info)
+{
+       if (!edid_info)
+               return;
+       rx_parse_blk0_print(edid_info);
+       rx_cea_ext_parse_print(&edid_info->cea_ext_info);
+
+       rx_pr("CEA ext blk free size: %d\n", edid_info->free_size);
+       rx_pr("CEA ext blk total free size(include dtd size): %d\n",
+               edid_info->total_free_size);
+       rx_pr("CEA ext blk dtd size: %d\n", edid_info->dtd_size);
+}
+
+void rx_data_blk_index_print(struct cta_data_blk_info *db_info)
+{
+       if (!db_info)
+               return;
+       rx_pr("%-7d\t 0x%-5X\t %-30s\t 0x%-8X\t %d\n",
+               db_info->cta_blk_index,
+               db_info->tag_code,
+               rx_get_cta_blk_name(db_info->tag_code),
+               db_info->offset,
+               db_info->blk_len);
+}
+
+void rx_blk_index_print(struct cta_blk_parse_info *blk_info)
+{
+       int i;
+
+       if (!blk_info)
+               return;
+       rx_pr("****CTA Data Block Index****\n");
+       rx_pr("%-7s\t %-7s\t %-30s\t %-10s\t %s\n",
+               "blk_idx", "blk_tag", "blk_name",
+               "blk_offset", "blk_len");
+       for (i = 0; i < blk_info->data_blk_num; i++)
+               rx_data_blk_index_print(&blk_info->db_info[i]);
+}
+
 int rx_set_hdr_lumi(unsigned char *data, int len)
 {
        if ((data == NULL) || (len == 0))
@@ -2729,3 +3129,682 @@ void rx_edid_physical_addr(int a, int b, int c, int d)
 }
 EXPORT_SYMBOL(rx_edid_physical_addr);
 
+unsigned char rx_get_cea_dtd_size(unsigned char *cur_edid, unsigned int size)
+{
+       unsigned char dtd_block_offset;
+       unsigned char dtd_size = 0;
+
+       if (cur_edid == NULL)
+               return 0;
+       /* get description offset */
+       dtd_block_offset =
+               cur_edid[EDID_BLOCK1_OFFSET + EDID_DESCRIP_OFFSET];
+       dtd_block_offset += EDID_BLOCK1_OFFSET;
+       if (log_level & VIDEO_LOG)
+               rx_pr("%s dtd offset start:%d\n", __func__, dtd_block_offset);
+       /* dtd first two bytes are pixel clk != 0 */
+       while ((dtd_block_offset+1 < size-1) &&
+               (cur_edid[dtd_block_offset] ||
+               cur_edid[dtd_block_offset+1])) {
+               dtd_block_offset += DETAILED_TIMING_LEN;
+               if (dtd_block_offset >= size-1)
+                       break;
+               dtd_size += DETAILED_TIMING_LEN;
+       }
+       if (log_level & VIDEO_LOG)
+               rx_pr("%s block_start end:%d\n", __func__, dtd_block_offset);
+
+       return dtd_size;
+}
+
+/* rx_get_total_free_size
+ * get total free size including dtd
+ */
+unsigned char rx_edid_total_free_size(unsigned char *cur_edid,
+       unsigned int size)
+{
+       unsigned char dtd_block_offset;
+
+       if (cur_edid == NULL)
+               return 0;
+       /* get description offset */
+       dtd_block_offset =
+               cur_edid[EDID_BLOCK1_OFFSET + EDID_DESCRIP_OFFSET];
+       dtd_block_offset += EDID_BLOCK1_OFFSET;
+       if (log_level & VIDEO_LOG)
+               rx_pr("%s total free size: %d\n", __func__,
+                       size - dtd_block_offset - 1);
+       /* free size except checksum */
+       return (size - dtd_block_offset - 1);
+}
+
+bool rx_set_earc_cap_ds(unsigned char *data, unsigned int len)
+{
+       new_earc_cap_ds = true;
+       memset(recv_earc_cap_ds, 0, sizeof(recv_earc_cap_ds));
+       if ((data == NULL) ||
+               (len > EARC_CAP_DS_MAX_LENGTH)) {
+               return false;
+       }
+
+       memcpy(recv_earc_cap_ds, data, len);
+       earc_cap_ds_len = len;
+
+       rx_pr("*update earc cap_ds to edid*\n");
+       hdmi_rx_top_edid_update();
+       /* if currently in arc port, don't reset hpd */
+       if (rx.open_fg && (rx.port != rx.arc_port)) {
+               if (earc_cap_ds_update_hpd_en)
+                       rx_send_hpd_pulse();
+       } else {
+               pre_port = 0xff;
+               rx_pr("update cap_ds later, in ARC port:%s\n",
+                       rx.port == rx.arc_port ? "Y" : "N");
+       }
+       return true;
+}
+EXPORT_SYMBOL(rx_set_earc_cap_ds);
+
+/* cap_info need to be cleared firstly */
+static bool parse_earc_cap_ds(unsigned char *cap_ds_in, unsigned int len_in,
+       unsigned char *raw_edid_out, unsigned int *len_out,
+       struct earc_cap_ds *cap_info)
+{
+       enum earc_cap_block_id edid_byte = EARC_CAP_DS_END_MARKER;
+       unsigned int index_in = 0;
+       unsigned int index_out = 0;
+       unsigned char i = 0;
+
+       if (!cap_ds_in || (len_in == 0) || (len_in > EARC_CAP_DS_MAX_LENGTH)) {
+               rx_pr("invalid eARC Cap Data Structure\n");
+               return false;
+       }
+       if (!cap_info)
+               return false;
+       if (cap_ds_in[index_in++] != CAP_DS_VER) {
+               rx_pr("invalid eARC Cap Data Structure version\n");
+               return false;
+       }
+       if (len_out)
+               *len_out = 0;
+       cap_info->cap_ds_len = len_in;
+       cap_info->cap_ds_ver = CAP_DS_VER;
+
+       if (index_in < len_in)
+               edid_byte = cap_ds_in[index_in];
+
+       while ((edid_byte != EARC_CAP_DS_END_MARKER) &&
+               (index_in < len_in) &&
+               (i < EARC_CAP_BLOCK_MAX)) {
+               switch (edid_byte) {
+               case EARC_CAP_BLOCK_ID_1:
+               case EARC_CAP_BLOCK_ID_2:
+               case EARC_CAP_BLOCK_ID_3:
+                       cap_info->cap_block[i].block_id = edid_byte;
+                       cap_info->cap_block[i].offset = index_in;
+                       cap_info->cap_block[i].payload_len =
+                               cap_ds_in[++index_in];
+                       /* payload index */
+                       index_in++;
+                       /* CAP_BLOCK1/2/3 maybe all need, currently only
+                        * consider CAP_BLOCK_ID=1
+                        */
+                       if (/* ((edid_byte == EARC_CAP_BLOCK_ID_1) || */
+                               /* (edid_byte == EARC_CAP_BLOCK_ID_2)) && */
+                               raw_edid_out &&
+                               len_out) {
+                               memcpy(&raw_edid_out[index_out],
+                                       &cap_ds_in[index_in],
+                                       cap_info->cap_block[i].payload_len);
+                               *len_out += cap_info->cap_block[i].payload_len;
+                       }
+                       index_in += cap_info->cap_block[i].payload_len;
+                       index_out += cap_info->cap_block[i].payload_len;
+                       i++;
+                       if (index_in < len_in)
+                               edid_byte = cap_ds_in[index_in];
+                       break;
+               /* case EARC_CAP_BLOCK_ID_0: */
+               default:
+                       edid_byte = EARC_CAP_DS_END_MARKER;
+                       break;
+               }
+       }
+
+       if (raw_edid_out && len_out && *len_out)
+               parse_cta_data_block(raw_edid_out, *len_out,
+                       &cap_info->blk_parse_info);
+       return true;
+}
+
+void cap_blk_index_print(struct cap_block_s *cap_blk)
+{
+       if (!cap_blk)
+               return;
+
+       rx_pr("%-6d\t %-10d\t %d\n",
+               cap_blk->block_id,
+               cap_blk->offset,
+               cap_blk->payload_len+1);
+}
+
+void earc_cap_ds_index_print(struct earc_cap_ds *cap_info)
+{
+       unsigned char i = 0;
+
+       if (!cap_info)
+               return;
+       rx_pr("****eARC Cap Data Sturct Index****\n");
+       rx_pr("cap_ds_len: %d\n", cap_info->cap_ds_len);
+       rx_pr("cap_ds_ver: %d\n", cap_info->cap_ds_ver);
+       if (cap_info->cap_ds_len > 1)
+               rx_pr("%-6s\t %-10s\t %s\n",
+                       "Blk_ID", "Blk_Offset", "blk_len");
+       while ((i < EARC_CAP_BLOCK_MAX) && cap_info->cap_block[i].block_id) {
+               cap_blk_index_print(&cap_info->cap_block[i]);
+               i++;
+       }
+}
+
+void earc_cap_blk_info_print(struct cta_blk_parse_info *blk_info)
+{
+       if (!blk_info)
+               return;
+       rx_parse_print_adb(&blk_info->audio_db);
+       rx_parse_print_spk_alloc(&blk_info->speaker_alloc);
+       /* VSADB, RCDB, SLDB */
+}
+
+void rx_prase_earc_capds_dbg(void)
+{
+       bool ret;
+       unsigned char raw_edid_out[EARC_CAP_DS_MAX_LENGTH] = {0};
+       unsigned int raw_edid_len = 0;
+       struct earc_cap_ds cap_info;
+
+       memset(&cap_info, 0, sizeof(struct earc_cap_ds));
+       ret = parse_earc_cap_ds(recv_earc_cap_ds, earc_cap_ds_len,
+               raw_edid_out, &raw_edid_len, &cap_info);
+
+       if (!ret)
+               return;
+       earc_cap_ds_index_print(&cap_info);
+       if (raw_edid_len)
+               earc_cap_blk_info_print(&cap_info.blk_parse_info);
+}
+
+/* extract data block with certain tag from EDID */
+uint8_t *edid_tag_extract(uint8_t *p_edid, uint16_t tagid)
+{
+       unsigned int index = EDID_EXT_BLK_OFF;
+       uint8_t tag_length;
+       int tag_code;
+
+       if (!p_edid)
+               return NULL;
+        /* check if a cea extension block */
+       if (p_edid[126]) {
+               index += 4;
+               while (index < EDID_SIZE) {
+                       tag_code = rx_get_tag_code(p_edid+index);
+                       tag_length = BLK_LENGTH(p_edid[index]);
+                       if (tag_code == tagid)
+                               return &p_edid[index];
+                       index += tag_length + 1;
+               }
+       }
+       return NULL;
+}
+
+/* extract data block with certain tag from block buf */
+uint8_t *data_blk_extract(uint8_t *p_buf, unsigned int buf_len, uint16_t tagid)
+{
+       unsigned int index = 0;
+       uint8_t tag_length;
+       uint8_t tag_code;
+
+       if (!p_buf || (buf_len > EDID_SIZE) ||
+               (buf_len == 0))
+               return NULL;
+       while (index < buf_len) {
+               /* Get the tag and length */
+               tag_code = rx_get_tag_code(p_buf+index);
+               tag_length = BLK_LENGTH(p_buf[index]);
+               if (tagid == tag_code)
+                       return &p_buf[index];
+               index += tag_length + 1;
+       }
+       return NULL;
+}
+
+/* combine short audio descriptors,
+ * see FigureH-3 of HDMI2.1 SPEC
+ */
+unsigned char *compose_audio_db(uint8_t *aud_db, uint8_t *add_buf)
+{
+       uint8_t aud_db_len;
+       uint8_t add_buf_len;
+       uint8_t payload_len;
+       uint8_t tmp_aud[DB_LEN_MAX-1] = {0};
+       uint8_t *tmp_buf = add_buf;
+
+       uint8_t i, j;
+       uint8_t idx = 1;
+       enum edid_audio_format_e aud_fmt;
+       enum edid_audio_format_e tmp_fmt;
+
+       if (!aud_db || !add_buf)
+               return NULL;
+       memset(com_aud, 0, sizeof(com_aud));
+       aud_db_len = BLK_LENGTH(aud_db[0])+1;
+       add_buf_len = BLK_LENGTH(add_buf[0])+1;
+
+       for (i = 1; (i < aud_db_len) && (idx < DB_LEN_MAX-1); i += SAD_LEN) {
+               aud_fmt = (aud_db[i] & 0x78) >> 3;
+               for (j = 1; j < add_buf_len; j += SAD_LEN) {
+                       tmp_fmt = (tmp_buf[j] & 0x78) >> 3;
+                       if (aud_fmt == tmp_fmt)
+                               break;
+               }
+               /* copy this audio data to payload */
+               if (j == add_buf_len)
+                       /* not find this fmt in add_buf */
+                       memcpy(com_aud+idx, aud_db+i, SAD_LEN);
+               else {
+                       /* find this fmt in add_buf */
+                       memcpy(com_aud+idx, tmp_buf+j, SAD_LEN);
+                       /* delete this fmt from add_buf */
+                       memcpy(tmp_aud+1, tmp_buf+1, j-1);
+                       memcpy(tmp_aud+j, tmp_buf+j+SAD_LEN,
+                               add_buf_len-j-SAD_LEN);
+                       add_buf_len -= SAD_LEN;
+                       tmp_buf = tmp_aud;
+               }
+               idx += SAD_LEN;
+       }
+       /* copy ramin Short Audio Descriptors
+        * in add_buf, except blk header
+        */
+       memcpy(com_aud+idx, tmp_buf+1, add_buf_len-1);
+       payload_len = (idx - 1) + (add_buf_len - 1);
+       /* data blk header */
+       com_aud[0] = (AUDIO_TAG << 5) | payload_len;
+
+       if (log_level & EDID_LOG) {
+               rx_pr("++++after compose, audio data blk:\n");
+               for (i = 0; i < payload_len+1; i++)
+                       rx_pr("%02x", com_aud[i]);
+               rx_pr("\n");
+       }
+       return com_aud;
+}
+
+/* param[add_buf]: contain only one data blk.
+ * param[blk_idx]: sequence number of the data blk
+ * 1.if the data blk is not present in edid, then
+ * add this data blk according to add_blk_idx,
+ * otherwise compose and replace this data blk.
+ * 2.if blk_idx is 0xFF, then add this data blk
+ * after the last data blk, otherwise insert it
+ * in the blk_idx place.
+ */
+void splice_data_blk_to_edid(uint8_t *p_edid, uint8_t *add_buf,
+       uint8_t blk_idx)
+{
+       /* uint8_t *tag_data_blk = NULL; */
+       uint8_t *add_data_blk = NULL;
+       uint8_t tag_db_len = 0;
+       uint8_t add_db_len = 0;
+       uint8_t diff_len = 0;
+       uint16_t tag_code = 0;
+       uint8_t tag_offset = 0;
+
+       int free_size = 0;
+       uint8_t total_free_size = 0;
+       uint8_t dtd_size = 0;
+       uint8_t free_space_off;
+       unsigned int i = 0;
+       struct cea_ext_parse_info cea_ext;
+       uint8_t num;
+
+       if (!p_edid || !add_buf)
+               return;
+
+       free_size = rx_edid_free_size(p_edid, EDID_SIZE);
+       if (free_size < 0) {
+               rx_pr("wrong edid\n");
+               return;
+       }
+       total_free_size =
+               rx_edid_total_free_size(p_edid, EDID_SIZE);
+       dtd_size = rx_get_cea_dtd_size(p_edid, EDID_SIZE);
+
+       tag_code = (add_buf[0] >> 5) & 0x7;
+       if (tag_code == USE_EXTENDED_TAG)
+               tag_code = (tag_code << 8) | add_buf[1];
+       /* tag_data_blk = edid_tag_extract(p_edid, tag_code); */
+       tag_offset = rx_get_ceadata_offset(p_edid, add_buf);
+
+       /* if (!tag_data_blk) { */
+       if (tag_offset == 0) {
+               /* not find the data blk, add it to edid */
+               add_db_len = BLK_LENGTH(add_buf[0])+1;
+               edid_parse_cea_ext_block(p_edid+EDID_EXT_BLK_OFF,
+                       &cea_ext);
+               /* decide to add db after which data blk */
+               num =
+                       cea_ext.blk_parse_info.data_blk_num;
+
+               if (blk_idx >= num)
+                       /* add after the last data blk */
+                       tag_offset =
+                               cea_ext.blk_parse_info.db_info[num-1].offset+
+                               cea_ext.blk_parse_info.db_info[num-1].blk_len;
+               else
+                       /* insert in blk_idx */
+                       tag_offset =
+                               cea_ext.blk_parse_info.db_info[blk_idx].offset;
+               tag_offset += EDID_BLOCK1_OFFSET;
+               if (add_db_len <= free_size) {
+                       /* move data behind added data block, except checksum */
+                       for (i = 0; i < EDID_SIZE-tag_offset-add_db_len-1; i++)
+                               p_edid[255-i-1] =
+                                       p_edid[255-i-1-add_db_len];
+               } else if (en_take_dtd_space) {
+                       if (add_db_len > total_free_size) {
+                               rx_pr("no enough space for splicing3, abort\n");
+                               return;
+                       }
+                       /* actually, total free size = free_size + dtd_size,
+                        * add_db_len won't excess 32bytes, so may excess
+                        * one dtd length, but mustn't excess 2 dtd length.
+                        * need clear the replaced dtd to 0
+                        */
+                       if (add_db_len <= free_size + DETAILED_TIMING_LEN) {
+                               free_space_off =
+                                       255-free_size-DETAILED_TIMING_LEN;
+                               memset(&p_edid[free_space_off], 0,
+                                       DETAILED_TIMING_LEN);
+                       } else {
+                               free_space_off =
+                                       255-free_size-2*DETAILED_TIMING_LEN;
+                               memset(&p_edid[free_space_off], 0,
+                                       2*DETAILED_TIMING_LEN);
+                       }
+                       /* move data behind current data
+                        * block, except checksum
+                        */
+                       for (i = 0; i < EDID_SIZE-tag_offset-add_db_len-1; i++)
+                               p_edid[255-i-1] =
+                                       p_edid[255-i-1-add_db_len];
+               } else {
+                       rx_pr("no enough space for splicing4, abort\n");
+                       return;
+               }
+               /* dtd offset modify */
+               p_edid[EDID_BLOCK1_OFFSET + EDID_DESCRIP_OFFSET]
+                       += add_db_len;
+               /* copy added data block */
+               memcpy(p_edid + tag_offset, add_buf, add_db_len);
+       } else {
+               /* tag_db_len = BLK_LENGTH(tag_data_blk[0])+1; */
+               tag_db_len = BLK_LENGTH(p_edid[tag_offset])+1;
+               add_data_blk = add_buf;
+               /* compose and replace data blk */
+               if (tag_code == AUDIO_TAG) {
+                       /* compose audio data blk */
+                       add_data_blk =
+                               compose_audio_db(&p_edid[tag_offset], add_buf);
+                               /* compose_audio_db(tag_data_blk, add_buf); */
+               }
+               /* replace data blk */
+               if (!add_data_blk)
+                       return;
+               add_db_len = BLK_LENGTH(add_data_blk[0])+1;
+               if (tag_db_len >= add_db_len) {
+                       /* move data behind current data
+                        * block, except checksum
+                        */
+                       for (i = 0; i < EDID_SIZE-tag_offset-tag_db_len-1; i++)
+                               p_edid[tag_offset+i+add_db_len] =
+                                       p_edid[tag_offset+i+tag_db_len];
+                       /* need clear the new free space to 0 */
+                       free_size += (tag_db_len-add_db_len);
+                       free_space_off = 255-free_size;
+                       memset(&p_edid[free_space_off], 0, free_size);
+               } else if (add_db_len - tag_db_len > DB_LEN_MAX-1) {
+                       /* data block is maxmium 32bytes, minimum 1byte */
+                       rx_pr("illegal add data blk len: %d\n", add_db_len);
+                       return;
+               } else if (add_db_len - tag_db_len <= free_size) {
+                       /* move data behind current data
+                        * block, except checksum
+                        */
+                       for (i = 0; i < EDID_SIZE-tag_offset-add_db_len-1; i++)
+                               p_edid[255-i-1] =
+                                       p_edid[255-i-1-(add_db_len-tag_db_len)];
+               } else if (en_take_dtd_space) {
+                       diff_len = add_db_len - tag_db_len;
+                       if (diff_len > total_free_size) {
+                               rx_pr("no enough space for splicing, abort\n");
+                               return;
+                       }
+                       /* actually, total free size = free_size + dtd_size,
+                        * diff_len won't excess 31bytes, so may excess
+                        * one dtd length, but mustn't excess 2 dtd length.
+                        * need clear the replaced dtd to 0
+                        */
+                       if (diff_len <= free_size + DETAILED_TIMING_LEN) {
+                               free_space_off =
+                                       255-free_size-DETAILED_TIMING_LEN;
+                               memset(&p_edid[free_space_off], 0,
+                                       DETAILED_TIMING_LEN);
+                       } else {
+                               free_space_off =
+                                       255-free_size-2*DETAILED_TIMING_LEN;
+                               memset(&p_edid[free_space_off], 0,
+                                       2*DETAILED_TIMING_LEN);
+                       }
+                       /* move data behind current data
+                        * block, except checksum
+                        */
+                       for (i = 0; i < EDID_SIZE-tag_offset-add_db_len-1; i++)
+                               p_edid[255-i-1] =
+                                       p_edid[255-i-1-(add_db_len-tag_db_len)];
+               } else {
+                       rx_pr("no enough space for splicing2, abort\n");
+                       return;
+               }
+               /* dtd offset modify */
+               p_edid[EDID_BLOCK1_OFFSET + EDID_DESCRIP_OFFSET]
+                       += (add_db_len - tag_db_len);
+               /* copy added data block */
+               memcpy(p_edid + tag_offset, add_data_blk, add_db_len);
+       }
+       if (log_level & EDID_LOG) {
+               rx_pr("++++edid data after splice:\n");
+               for (i = 0; i < EDID_SIZE; i++)
+                       rx_pr("%02x", p_edid[i]);
+               rx_pr("\n");
+       }
+}
+
+/* param[add_buf] may contain multi data blk,
+ * search the blk filtered by tag, and then
+ * splice it with edid
+ */
+void splice_tag_db_to_edid(uint8_t *p_edid, uint8_t *add_buf,
+       uint8_t buf_len, uint16_t tagid)
+{
+       uint8_t *tag_data_blk = NULL;
+       unsigned int i;
+
+       if (!p_edid || !add_buf)
+               return;
+       tag_data_blk = data_blk_extract(add_buf, buf_len, tagid);
+       if (!tag_data_blk)
+               return;
+       if (log_level & EDID_LOG) {
+               rx_pr("++++extracted data blk(tag=0x%x):\n", tagid);
+               for (i = 0; i < BLK_LENGTH(tag_data_blk[0]) + 1; i++)
+                       rx_pr("%02x", tag_data_blk[i]);
+               rx_pr("\n");
+       }
+       /* if db not exist in edid, then add it to the end */
+       splice_data_blk_to_edid(p_edid, tag_data_blk, 0xFF);
+}
+
+/* romove cta data blk which tag = tagid */
+void edid_rm_db_by_tag(uint8_t *p_edid, uint16_t tagid)
+{
+       int tag_offset;
+       unsigned char tag_len;
+       unsigned int i;
+       int free_size;
+       unsigned char free_space_off;
+       uint8_t *tag_data_blk = NULL;
+
+       if (!p_edid)
+               return;
+       free_size = rx_edid_free_size(p_edid, EDID_SIZE);
+       if (free_size < 0) {
+               rx_pr("wrong edid\n");
+               return;
+       }
+       tag_data_blk = edid_tag_extract(p_edid, tagid);
+       if (!tag_data_blk) {
+               rx_pr("no this data blk in edid\n");
+               return;
+       }
+       tag_offset = tag_data_blk - p_edid;
+       tag_len = BLK_LENGTH(tag_data_blk[0]) + 1;
+       /* move data behind the removed data block
+        * forward, except checksum & free size
+        */
+       for (i = tag_offset; i < 255-tag_len-free_size; i++)
+               p_edid[i] = p_edid[i+tag_len];
+       free_size += tag_len;
+       free_space_off = 255 - free_size;
+       /* clear new free space to zero */
+       memset(&p_edid[free_space_off], 0, tag_len);
+       /* dtd offset modify */
+       p_edid[EDID_BLOCK1_OFFSET + EDID_DESCRIP_OFFSET]
+               -= tag_len;
+       if (log_level & EDID_LOG) {
+               rx_pr("++++edid data after rm db:\n");
+               for (i = 0; i < EDID_SIZE; i++)
+                       rx_pr("%02x", p_edid[i]);
+               rx_pr("\n");
+       }
+}
+
+/* param[blk_idx]: start from 0
+ * the sequence index of the data blk to be removed
+ */
+void edid_rm_db_by_idx(uint8_t *p_edid, uint8_t blk_idx)
+{
+       struct cea_ext_parse_info ext_blk_info;
+       int tag_offset;
+       unsigned char tag_len;
+       unsigned int i;
+       int free_size;
+       unsigned char free_space_off;
+
+       if (!p_edid)
+               return;
+       free_size = rx_edid_free_size(p_edid, EDID_SIZE);
+       if (free_size < 0) {
+               rx_pr("wrong edid\n");
+               return;
+       }
+       edid_parse_cea_ext_block(p_edid+EDID_EXT_BLK_OFF,
+               &ext_blk_info);
+       if (blk_idx >= ext_blk_info.blk_parse_info.data_blk_num) {
+               rx_pr("no this index data blk in edid\n");
+               return;
+       }
+       tag_offset = EDID_EXT_BLK_OFF +
+               ext_blk_info.blk_parse_info.db_info[blk_idx].offset;
+       tag_len =
+               ext_blk_info.blk_parse_info.db_info[blk_idx].blk_len;
+       /* move data behind the removed data block
+        * forward, except checksum & free size
+        */
+       for (i = tag_offset; i < 255-tag_len-free_size; i++)
+               p_edid[i] = p_edid[i+tag_len];
+
+       free_size += tag_len;
+       free_space_off = 255 - free_size;
+       /* clear new free space to zero */
+       memset(&p_edid[free_space_off], 0, tag_len);
+       /* dtd offset modify */
+       p_edid[EDID_BLOCK1_OFFSET + EDID_DESCRIP_OFFSET]
+               -= tag_len;
+       if (log_level & EDID_LOG) {
+               rx_pr("++++edid data after rm db:\n");
+               for (i = 0; i < EDID_SIZE; i++)
+                       rx_pr("%02x", p_edid[i]);
+               rx_pr("\n");
+       }
+}
+
+void edid_splice_earc_capds(unsigned char *p_edid,
+       unsigned char *earc_cap_ds, unsigned int len)
+{
+       bool ret;
+       unsigned char raw_edid_out[EARC_CAP_DS_MAX_LENGTH] = {0};
+       unsigned int raw_edid_len = 0;
+       struct earc_cap_ds cap_info;
+       unsigned int i;
+
+       if (!p_edid || !earc_cap_ds ||
+               (len == 0) || (len > EARC_CAP_DS_MAX_LENGTH)) {
+               rx_pr("invalid splice data, abort\n");
+               return;
+       }
+       memset(&cap_info, 0, sizeof(struct earc_cap_ds));
+       ret = parse_earc_cap_ds(earc_cap_ds, len,
+               raw_edid_out, &raw_edid_len, &cap_info);
+       if (!ret) {
+               rx_pr("earc cap ds parse failed\n");
+               return;
+       }
+       if (log_level & EDID_LOG) {
+               rx_pr("++++raw cta blks extracted from capds:\n");
+               for (i = 0; i < raw_edid_len; i++)
+                       rx_pr("%02x", raw_edid_out[i]);
+               rx_pr("\n");
+       }
+       splice_tag_db_to_edid(p_edid, raw_edid_out,
+               raw_edid_len, AUDIO_TAG);
+       splice_tag_db_to_edid(p_edid, raw_edid_out,
+               raw_edid_len, SPEAKER_TAG);
+}
+
+void edid_splice_earc_capds_dbg(uint8_t *p_edid)
+{
+       struct edid_info_s edid_info;
+
+       if (!p_edid)
+               return;
+       memset(&edid_info, 0, sizeof(struct edid_info_s));
+       edid_splice_earc_capds(p_edid,
+               recv_earc_cap_ds, earc_cap_ds_len);
+       rx_edid_parse(p_edid, &edid_info);
+       rx_edid_parse_print(&edid_info);
+       rx_blk_index_print(&edid_info.cea_ext_info.blk_parse_info);
+}
+
+void edid_splice_data_blk_dbg(uint8_t *p_edid, uint8_t idx)
+{
+       struct edid_info_s edid_info;
+
+       if (!p_edid)
+               return;
+       memset(&edid_info, 0, sizeof(struct edid_info_s));
+       splice_data_blk_to_edid(p_edid, recv_earc_cap_ds, idx);
+       rx_edid_parse(p_edid, &edid_info);
+       rx_edid_parse_print(&edid_info);
+       rx_blk_index_print(&edid_info.cea_ext_info.blk_parse_info);
+}
+
index 9a3d43f..91e2c23 100644 (file)
 #ifndef _HDMI_RX_EDID_H_
 #define _HDMI_RX_EDID_H_
 
+#define EDID_EXT_BLK_OFF       128
 #define EDID_SIZE                      256
 #define EDID_HDR_SIZE          7
 #define EDID_HDR_HEAD_LEN      4
 #define MAX_HDR_LUMI_LEN       3
 #define MAX_EDID_BUF_SIZE      512
 
-/* CEA861F Table 44~46 CEA data block tag code*/
+/* CTA-861G Table 54~57 CTA data block tag codes */
 /* tag code 0x0: reserved */
 #define AUDIO_TAG 0x1
 #define VIDEO_TAG 0x2
 #define VENDOR_TAG 0x3
+/* tag of HF-VSDB is the same as VSDB
+ * so add an offset(0xF0) for HF-VSDB
+ */
+#define HF_VSDB_OFFSET 0xF0
+#define HF_VENDOR_DB_TAG (VENDOR_TAG + HF_VSDB_OFFSET)
 #define SPEAKER_TAG 0x4
 /* VESA Display Transfer Characteristic Data Block */
-#define VESA_TAG 0x5
+#define VDTCDB_TAG 0x5
 /* tag code 0x6: reserved */
 #define USE_EXTENDED_TAG 0x7
 
 #define VCDB_TAG 0 /* video capability data block */
 #define VSVDB_TAG 1 /* Vendor-Specific Video Data Block */
 #define VDDDB_TAG 2 /* VESA Display Device Data Block */
-#define VVTDB_TAG 3 /* VESA Video Timing Block Extension */
-/* extend tag code 0x4: Reserved for HDMI Video Data Block*/
+#define VVTBE_TAG 3 /* VESA Video Timing Block Extension */
+/* extend tag code 0x4: Reserved for HDMI Video Data Block */
 #define CDB_TAG 5 /* Colorimetry Data Block */
-#define HDR_TAG 6 /* HDR Static Metadata Data Block */
-/* extend tag code 7-12: reserved */
+#define HDR_STATIC_TAG 6 /* HDR Static Metadata Data Block */
+#define HDR_DYNAMIC_TAG 7 /* HDR Dynamic Metadata Data Block */
+/* extend tag code 8-12: reserved */
 #define VFPDB_TAG 13 /* Video Format Preference Data Block */
 #define Y420VDB_TAG 14 /* YCBCR 4:2:0 Video Data Block */
 #define Y420CMDB_TAG 15 /* YCBCR 4:2:0 Capability Map Data Block */
-/* extend tag code 16: Reserved */
+/* extend tag code 16: Reserved for CTA Miscellaneous Audio Fields */
 #define VSADB_TAG 17 /* Vendor-Specific Audio Data Block */
-/* extend tag code 18~31: Reserved */
+/* extend tag code 18: Reserved for HDMI Audio Data Block */
+#define RCDB_TAG 19 /* Room Configuration Data Block */
+#define SLDB_TAG 20    /* Speaker Location Data Block */
+/* extend tag code 21~31: Reserved */
 #define IFDB_TAG 32 /* infoframe data block */
 #define HDMI_VIC420_OFFSET 0x100
 #define HDMI_3D_OFFSET 0x180
 #define HDMI_VESA_OFFSET 0x200
 
+/* eARC Rx Capabilities Data Structure version */
+#define CAP_DS_VER 0x1
+/* eARC Rx Capabilities Data Structure Maximum Length */
+#define EARC_CAP_DS_MAX_LENGTH 256
+/* eARC Rx Capability data structure End Marker */
+#define EARC_CAP_DS_END_MARKER 0x00
+#define EARC_CAP_BLOCK_MAX 3
+#define DATA_BLK_MAX_NUM 32
+#define TAG_MAX 0xFF
+/* data block max length(include head): 0x1F+1 */
+#define DB_LEN_MAX 32
+/* short audio descriptor length */
+#define SAD_LEN 3
+#define BLK_LENGTH(a) (a & 0x1F)
 
 enum edid_audio_format_e {
        AUDIO_FORMAT_HEADER,
@@ -81,6 +105,16 @@ enum edid_tag_e {
        EDID_TAG_HDR = ((0x7<<8)|6),
 };
 
+union bit_rate_u {
+       struct pcm_t {
+               unsigned char size_16bit:1;
+               unsigned char size_20bit:1;
+               unsigned char size_24bit:1;
+               unsigned char size_reserv:5;
+       } pcm;
+       unsigned char others;
+};
+
 struct edid_audio_block_t {
        unsigned char max_channel:3;
        unsigned char format_code:4;
@@ -94,15 +128,7 @@ struct edid_audio_block_t {
        unsigned char freq_176_4khz:1;
        unsigned char freq_192khz:1;
        unsigned char freq_reserv:1;
-       union bit_rate_u {
-               struct pcm_t {
-                       unsigned char size_16bit:1;
-                       unsigned char size_20bit:1;
-                       unsigned char size_24bit:1;
-                       unsigned char size_reserv:5;
-               } pcm;
-               unsigned char others;
-       } bit_rate;
+       union bit_rate_u bit_rate;
 };
 
 struct edid_hdr_block_t {
@@ -151,6 +177,7 @@ struct audio_db_s {
        struct edid_audio_block_t sad[15];
 };
 
+/* may need extend spker alloc from CTA-SPEC */
 /* speaker allocation data block: 3 bytes*/
 struct speaker_alloc_db_s {
        unsigned char flw_frw:1;
@@ -358,38 +385,14 @@ struct dv_vsvdb_s {
        uint8_t dm_minor_ver;
 };
 
-struct edid_info_s {
-       /* 8 */
-       unsigned char manufacturer_name[3];
-       /* 10 */
-       unsigned int product_code;
-       /* 12 */
-       unsigned int serial_number;
-       /* 16 */
-       unsigned char product_week;
-       unsigned int product_year;
-       unsigned char edid_version;
-       unsigned char edid_revision;
-       /* 54 + 18 * x */
-       struct detailed_timing_desc descriptor1;
-       struct detailed_timing_desc descriptor2;
-       /* 54 + 18 * x */
-       unsigned char monitor_name[13];
-       unsigned int max_sup_pixel_clk;
-       uint8_t extension_flag;
-       /* 127 */
-       unsigned char block0_chk_sum;
+struct cta_data_blk_info {
+       unsigned char cta_blk_index;
+       uint16_t tag_code;
+       unsigned char offset;
+       unsigned char blk_len;
+};
 
-       /* CEA extension */
-       /* CEA header */
-       unsigned char cea_tag;
-       unsigned char cea_revision;
-       unsigned char dtd_offset;
-       unsigned char underscan_sup:1;
-       unsigned char basic_aud_sup:1;
-       unsigned char ycc444_sup:1;
-       unsigned char ycc422_sup:1;
-       unsigned char native_dtd_num:4;
+struct cta_blk_parse_info {
        /* audio data block */
        struct video_db_s video_db;
        /* audio data block */
@@ -425,6 +428,63 @@ struct edid_info_s {
        bool contain_y420_cmdb;
        unsigned char y420_all_vic;
        unsigned char y420_cmdb_vic[31];
+
+       bool contain_vsadb;
+       unsigned int vsadb_ieee;
+       /* CTA-861-G 7.5.8 27-2-3 */
+       unsigned char vsadb_payload[22];
+
+       unsigned char data_blk_num;
+       struct cta_data_blk_info db_info[DATA_BLK_MAX_NUM];
+};
+
+/* CEA extension */
+struct cea_ext_parse_info {
+       /* CEA header */
+       unsigned char cea_tag;
+       unsigned char cea_revision;
+       unsigned char dtd_offset;
+       unsigned char underscan_sup:1;
+       unsigned char basic_aud_sup:1;
+       unsigned char ycc444_sup:1;
+       unsigned char ycc422_sup:1;
+       unsigned char native_dtd_num:4;
+
+       struct cta_blk_parse_info blk_parse_info;
+};
+
+struct edid_info_s {
+       /* 8 */
+       unsigned char manufacturer_name[3];
+       /* 10 */
+       unsigned int product_code;
+       /* 12 */
+       unsigned int serial_number;
+       /* 16 */
+       unsigned char product_week;
+       unsigned int product_year;
+       unsigned char edid_version;
+       unsigned char edid_revision;
+       /* 54 + 18 * x */
+       struct detailed_timing_desc descriptor1;
+       struct detailed_timing_desc descriptor2;
+       /* 54 + 18 * x */
+       unsigned char monitor_name[13];
+       unsigned int max_sup_pixel_clk;
+       uint8_t extension_flag;
+       /* 127 */
+       unsigned char block0_chk_sum;
+
+       struct cea_ext_parse_info cea_ext_info;
+
+       int free_size;
+       unsigned char total_free_size;
+       unsigned char dtd_size;
+};
+
+struct cta_blk_pair {
+       uint16_t tag_code;
+       char *blk_name;
 };
 
 struct edid_data_s {
@@ -440,6 +500,19 @@ enum tx_hpd_event_e {
        E_RCV = 2,
 };
 
+struct cap_block_s {
+       unsigned char block_id;
+       unsigned char payload_len;
+       unsigned char offset;
+};
+
+struct earc_cap_ds {
+       unsigned char cap_ds_len;
+       unsigned char cap_ds_ver;
+       struct cap_block_s cap_block[EARC_CAP_BLOCK_MAX];
+       struct cta_blk_parse_info blk_parse_info;
+};
+
 enum hdmi_vic_e {
        /* Refer to CEA 861-D */
        HDMI_UNKNOWN = 0,
@@ -615,10 +688,21 @@ enum hdmi_vic_e {
        HDMI_UNSUPPORT,
 };
 
+enum earc_cap_block_id {
+       EARC_CAP_BLOCK_ID_0 = 0,
+       EARC_CAP_BLOCK_ID_1 = 1,
+       EARC_CAP_BLOCK_ID_2 = 2,
+       EARC_CAP_BLOCK_ID_3 = 3
+};
+
 extern int edid_mode;
 extern int port_map;
 extern bool new_hdr_lum;
 extern bool atmos_edid_update_hpd_en;
+extern bool en_take_dtd_space;
+extern bool earc_cap_ds_update_hpd_en;
+extern unsigned char edid_temp[EDID_SIZE];
+
 int rx_set_hdr_lumi(unsigned char *data, int len);
 void rx_edid_physical_addr(int a, int b, int c, int d);
 unsigned char rx_parse_arc_aud_type(const unsigned char *buff);
@@ -626,8 +710,23 @@ extern unsigned int hdmi_rx_top_edid_update(void);
 unsigned char rx_get_edid_index(void);
 unsigned char *rx_get_edid(int edid_index);
 void edid_parse_block0(uint8_t *p_edid, struct edid_info_s *edid_info);
-void edid_parse_cea_block(uint8_t *p_edid, struct edid_info_s *edid_info);
+void edid_parse_cea_ext_block(uint8_t *p_edid,
+       struct cea_ext_parse_info *blk_parse_info);
+void rx_edid_parse(uint8_t *p_edid, struct edid_info_s *edid_info);
 void rx_edid_parse_print(struct edid_info_s *edid_info);
+void rx_blk_index_print(struct cta_blk_parse_info *blk_info);
+int rx_edid_free_size(uint8_t *cur_edid, int size);
+unsigned char rx_edid_total_free_size(unsigned char *cur_edid,
+       unsigned int size);
+unsigned char rx_get_cea_dtd_size(unsigned char *cur_edid, unsigned int size);
+bool rx_set_earc_cap_ds(unsigned char *data, unsigned int len);
+void rx_prase_earc_capds_dbg(void);
+void edid_splice_earc_capds(unsigned char *p_edid,
+       unsigned char *earc_cap_ds, unsigned int len);
+void edid_splice_earc_capds_dbg(uint8_t *p_edid);
+void edid_splice_data_blk_dbg(uint8_t *p_edid, uint8_t idx);
+void edid_rm_db_by_tag(uint8_t *p_edid, uint16_t tagid);
+void edid_rm_db_by_idx(uint8_t *p_edid, uint8_t blk_idx);
 void rx_modify_edid(unsigned char *buffer,
                                int len, unsigned char *addition);
 void rx_edid_update_audio_info(unsigned char *p_edid,
index 658e756..46ba1fa 100644 (file)
@@ -1730,6 +1730,10 @@ int rx_set_global_variable(const char *buf, int size)
                return pr_var(pll_lock_max, index);
        if (set_pr_var(tmpbuf, clock_lock_th, value, &index, ret))
                return pr_var(clock_lock_th, index);
+       if (set_pr_var(tmpbuf, en_take_dtd_space, value, &index, ret))
+               return pr_var(en_take_dtd_space, index);
+       if (set_pr_var(tmpbuf, earc_cap_ds_update_hpd_en, value, &index, ret))
+               return pr_var(earc_cap_ds_update_hpd_en, index);
        return 0;
 }
 
@@ -1841,6 +1845,8 @@ void rx_get_global_variable(const char *buf)
        pr_var(top_intr_maskn_value, i++);
        pr_var(pll_lock_max, i++);
        pr_var(clock_lock_th, i++);
+       pr_var(en_take_dtd_space, i++);
+       pr_var(earc_cap_ds_update_hpd_en, i++);
 }
 
 void skip_frame(unsigned int cnt)
@@ -2784,8 +2790,6 @@ int hdmirx_debug(const char *buf, int size)
        char *token;
        char *cur;
        int cnt = 0;
-       unsigned char edid_index;
-       unsigned char *pedid_data;
        struct edid_info_s edid_info;
 
        while ((buf[i]) && (buf[i] != ',') && (buf[i] != ' ')) {
@@ -2871,12 +2875,26 @@ int hdmirx_debug(const char *buf, int size)
        } else if (strncmp(input[0], "pktinfo", 7) == 0) {
                rx_debug_pktinfo(input);
        } else if (strncmp(tmpbuf, "parse_edid", 10) == 0) {
-               edid_index = rx_get_edid_index();
-               pedid_data = rx_get_edid(edid_index);
                memset(&edid_info, 0, sizeof(struct edid_info_s));
-               edid_parse_block0(pedid_data, &edid_info);
-               edid_parse_cea_block(pedid_data+128, &edid_info);
+               rx_edid_parse(edid_temp, &edid_info);
                rx_edid_parse_print(&edid_info);
+               rx_blk_index_print(&edid_info.cea_ext_info.blk_parse_info);
+       } else if (strncmp(tmpbuf, "parse_capds", 11) == 0) {
+               rx_prase_earc_capds_dbg();
+       } else if (strncmp(tmpbuf, "splice_capds", 12) == 0) {
+               edid_splice_earc_capds_dbg(edid_temp);
+       } else if (strncmp(tmpbuf, "splice_db", 9) == 0) {
+               if (kstrtou32(tmpbuf + 9, 16, &value) < 0)
+                       return -EINVAL;
+               edid_splice_data_blk_dbg(edid_temp, value);
+       } else if (strncmp(tmpbuf, "rm_db_tag", 9) == 0) {
+               if (kstrtou32(tmpbuf + 9, 16, &value) < 0)
+                       return -EINVAL;
+               edid_rm_db_by_tag(edid_temp, value);
+       } else if (strncmp(tmpbuf, "rm_db_idx", 9) == 0) {
+               if (kstrtou32(tmpbuf + 9, 16, &value) < 0)
+                       return -EINVAL;
+               edid_rm_db_by_idx(edid_temp, value);
        } else if (tmpbuf[0] == 'w') {
                rx_debug_wr_reg(buf, tmpbuf, i);
        } else if (tmpbuf[0] == 'r') {