From 7447ea231fd7e6fd9b41b2b5ea4f0a2abb2ec79d Mon Sep 17 00:00:00 2001 From: Hang Cheng Date: Thu, 16 May 2019 10:20:08 +0800 Subject: [PATCH] hdmirx: add edid data splice function [1/1] 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 --- .../amlogic/media/vin/tvin/hdmirx/hdmi_rx_drv.c | 54 +- .../amlogic/media/vin/tvin/hdmirx/hdmi_rx_drv.h | 3 +- .../amlogic/media/vin/tvin/hdmirx/hdmi_rx_edid.c | 1715 ++++++++++++++++---- .../amlogic/media/vin/tvin/hdmirx/hdmi_rx_edid.h | 197 ++- .../media/vin/tvin/hdmirx/hdmi_rx_wrapper.c | 30 +- 5 files changed, 1624 insertions(+), 375 deletions(-) diff --git a/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_drv.c b/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_drv.c index 06f7322..d22d90b 100644 --- a/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_drv.c +++ b/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_drv.c @@ -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); diff --git a/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_drv.h b/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_drv.h index be4d203..6524b32 100644 --- a/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_drv.h +++ b/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_drv.h @@ -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 { diff --git a/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_edid.c b/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_edid.c index dad96ab..9ce09bf 100644 --- a/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_edid.c +++ b/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_edid.c @@ -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); +} + diff --git a/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_edid.h b/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_edid.h index 9a3d43f..91e2c23 100644 --- a/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_edid.h +++ b/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_edid.h @@ -17,20 +17,26 @@ #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 @@ -38,22 +44,40 @@ #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, diff --git a/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_wrapper.c b/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_wrapper.c index 658e756..46ba1fa 100644 --- a/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_wrapper.c +++ b/drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_wrapper.c @@ -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') { -- 2.7.4