From 73c0a0b001bdf452625c1110972be2838b7ca612 Mon Sep 17 00:00:00 2001 From: Yi Zhou Date: Wed, 17 Oct 2018 17:07:55 +0800 Subject: [PATCH] hdmitx: add hdr10+ mechanism in hdmitx [2/2] PD#SWPL-869 Problem: need support hdr10+ Solution: 1. parse hdr10+ vsvdb 2. add hdr10+ vsif Verify: U200(G12A) Change-Id: I0761efa7cadcb73bd9394820b080c9a127d03382 Signed-off-by: Yi Zhou --- .../media/vout/hdmitx/hdmi_tx_20/hdmi_tx_edid.c | 31 +++- .../media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c | 175 +++++++++++++++++++-- .../media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c | 7 + .../amlogic/media/vout/vout_serve/vout2_serve.c | 5 + drivers/amlogic/media/vout/vout_serve/vout_serve.c | 5 + .../amlogic/media/vout/hdmi_tx/hdmi_tx_module.h | 3 +- include/linux/amlogic/media/vout/vinfo.h | 32 +++- 7 files changed, 239 insertions(+), 19 deletions(-) diff --git a/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_edid.c b/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_edid.c index 793bc45..41520ce 100644 --- a/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_edid.c +++ b/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_edid.c @@ -763,12 +763,17 @@ static void Edid_ParsingVendSpec(struct rx_cap *pRXCap, unsigned char *buf) { struct dv_info *dv = &pRXCap->dv_info; + struct hdr10_plus_info *hdr10_plus = &pRXCap->hdr10plus_info; unsigned char *dat = buf; unsigned char pos = 0; + unsigned int ieeeoui = 0; memset(dv, 0, sizeof(struct dv_info)); + memset(hdr10_plus, 0, sizeof(struct hdr10_plus_info)); + dv->block_flag = CORRECT; dv->length = dat[pos] & 0x1f; + hdr10_plus->length = dat[pos] & 0x1f; memcpy(dv->rawdata, dat, dv->length + 1); pos++; @@ -779,14 +784,23 @@ static void Edid_ParsingVendSpec(struct rx_cap *pRXCap, } pos++; - dv->ieeeoui = dat[pos++]; - dv->ieeeoui += dat[pos++] << 8; - dv->ieeeoui += dat[pos++] << 16; - if (dv->ieeeoui != DV_IEEE_OUI) { - dv->block_flag = ERROR_LENGTH; + ieeeoui = dat[pos++]; + ieeeoui += dat[pos++] << 8; + ieeeoui += dat[pos++] << 16; + +/*HDR10+ use vsvdb*/ + if (ieeeoui == HDR10_PLUS_IEEE_OUI) { + hdr10_plus->ieeeoui = ieeeoui; + hdr10_plus->application_version = dat[pos] & 0x3; + pos++; return; } + if (ieeeoui != DV_IEEE_OUI) { + dv->block_flag = ERROR_LENGTH; + return; + } + dv->ieeeoui = ieeeoui; dv->ver = (dat[pos] >> 5) & 0x7; /* Refer to DV 2.9 Page 27 */ if (dv->ver == 0) { @@ -1895,12 +1909,13 @@ next: static void hdrinfo_to_vinfo(struct vinfo_s *info, struct rx_cap *pRXCap) { unsigned int k, l; - + /*static hdr*/ info->hdr_info.hdr_support = (pRXCap->hdr_sup_eotf_sdr << 0) | (pRXCap->hdr_sup_eotf_hdr << 1) | (pRXCap->hdr_sup_eotf_smpte_st_2084 << 2) | (pRXCap->hdr_sup_eotf_hlg << 3); + /*dynamic hdr*/ for (l = 0; l < 4; l++) { if (pRXCap->hdr_dynamic_info[l].type == 0) { memset(&info->hdr_info.dynamic_info[l], @@ -1918,6 +1933,10 @@ static void hdrinfo_to_vinfo(struct vinfo_s *info, struct rx_cap *pRXCap) pRXCap->hdr_dynamic_info[l].optional_fields[k]; } } + /*hdr 10+*/ + memcpy(&(info->hdr_info.hdr10plus_info), + &(pRXCap->hdr10plus_info), sizeof(struct hdr10_plus_info)); + info->hdr_info.colorimetry_support = pRXCap->colorimetry_data; info->hdr_info.lumi_max = pRXCap->hdr_lum_max; diff --git a/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c b/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c index 6ecf080..98bd1d7 100644 --- a/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c +++ b/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c @@ -73,7 +73,10 @@ static void hdmitx_get_edid(struct hdmitx_dev *hdev); static void hdmitx_set_drm_pkt(struct master_display_info_s *data); static void hdmitx_set_vsif_pkt(enum eotf_type type, enum mode_type tunnel_mode, struct dv_vsif_para *data); -static void hdmitx_set_emp_pkt(void); +static void hdmitx_set_hdr10plus_pkt(unsigned int flag, + struct hdr10plus_para *data); +static void hdmitx_set_emp_pkt(unsigned char *data, + unsigned int type, unsigned int size); static int check_fbc_special(unsigned char *edid_dat); static struct vinfo_s *hdmitx_get_current_vinfo(void); @@ -86,6 +89,8 @@ struct vout_device_s hdmitx_vdev = { .dv_info = &(hdmitx_device.RXCap.dv_info), .fresh_tx_hdr_pkt = hdmitx_set_drm_pkt, .fresh_tx_vsif_pkt = hdmitx_set_vsif_pkt, + .fresh_tx_hdr10plus_pkt = hdmitx_set_hdr10plus_pkt, + .fresh_tx_emp_pkt = hdmitx_set_emp_pkt, }; struct hdmi_config_platform_data *hdmi_pdata; @@ -392,11 +397,12 @@ static void hdmi_physcial_size_update(struct hdmitx_dev *hdev) static void hdrinfo_to_vinfo(struct vinfo_s *info, struct hdmitx_dev *hdev) { unsigned int i, j; - + /*static hdr*/ info->hdr_info.hdr_support = (hdev->RXCap.hdr_sup_eotf_sdr << 0) | (hdev->RXCap.hdr_sup_eotf_hdr << 1) | (hdev->RXCap.hdr_sup_eotf_smpte_st_2084 << 2) | (hdev->RXCap.hdr_sup_eotf_hlg << 3); + /*dynamic hdr*/ for (i = 0; i < 4; i++) { if (hdev->RXCap.hdr_dynamic_info[i].type == 0) { memset(&info->hdr_info.dynamic_info[i], @@ -414,6 +420,10 @@ static void hdrinfo_to_vinfo(struct vinfo_s *info, struct hdmitx_dev *hdev) info->hdr_info.dynamic_info[i].optional_fields[j] = hdev->RXCap.hdr_dynamic_info[i].optional_fields[j]; } + /*hdr 10+*/ + memcpy(&(info->hdr_info.hdr10plus_info), + &(hdev->RXCap.hdr10plus_info), sizeof(struct hdr10_plus_info)); + info->hdr_info.colorimetry_support = hdev->RXCap.colorimetry_data; info->hdr_info.lumi_max = hdev->RXCap.hdr_lum_max; @@ -1516,34 +1526,173 @@ static void hdmitx_set_vsif_pkt(enum eotf_type type, } } } +static void hdmitx_set_hdr10plus_pkt(unsigned int flag, + struct hdr10plus_para *data) +{ + struct hdmitx_dev *hdev = &hdmitx_device; + unsigned char VEN_HB[3] = {0x81, 0x01, 0x1b}; + unsigned char VEN_DB[27] = {0x00}; -static void hdmitx_set_emp_pkt(void) + if ((!data) || (!flag)) { + hdev->HWOp.SetPacket(HDMI_PACKET_VEND, NULL, NULL); + hdev->HWOp.CntlConfig(hdev, CONF_AVI_BT2020, + CLR_AVI_BT2020); + return; + } + + VEN_DB[0] = 0x8b; + VEN_DB[1] = 0x84; + VEN_DB[2] = 0x90; + + VEN_DB[3] = ((data->application_version & 0x3) << 6) | + ((data->targeted_max_lum & 0x1f) << 1); + VEN_DB[4] = data->average_maxrgb; + VEN_DB[5] = data->distribution_values[0]; + VEN_DB[6] = data->distribution_values[1]; + VEN_DB[7] = data->distribution_values[2]; + VEN_DB[8] = data->distribution_values[3]; + VEN_DB[9] = data->distribution_values[4]; + VEN_DB[10] = data->distribution_values[5]; + VEN_DB[11] = data->distribution_values[6]; + VEN_DB[12] = data->distribution_values[7]; + VEN_DB[13] = data->distribution_values[8]; + VEN_DB[14] = ((data->num_bezier_curve_anchors & 0xf) << 4) | + ((data->knee_point_x >> 6) & 0xf); + VEN_DB[15] = ((data->knee_point_x & 0x3f) << 2) | + ((data->knee_point_y >> 8) & 0x3); + VEN_DB[16] = data->knee_point_y & 0xff; + VEN_DB[17] = data->bezier_curve_anchors[0]; + VEN_DB[18] = data->bezier_curve_anchors[1]; + VEN_DB[19] = data->bezier_curve_anchors[2]; + VEN_DB[20] = data->bezier_curve_anchors[3]; + VEN_DB[21] = data->bezier_curve_anchors[4]; + VEN_DB[22] = data->bezier_curve_anchors[5]; + VEN_DB[23] = data->bezier_curve_anchors[6]; + VEN_DB[24] = data->bezier_curve_anchors[7]; + VEN_DB[25] = data->bezier_curve_anchors[8]; + VEN_DB[26] = ((data->graphics_overlay_flag & 0x1) << 7)| + ((data->no_delay_flag & 0x1) << 6); + + hdev->HWOp.SetPacket(HDMI_PACKET_VEND, VEN_DB, VEN_HB); + hdev->HWOp.CntlConfig(hdev, CONF_AVI_BT2020, + SET_AVI_BT2020); + +} + +#define EMP_FIRST 0x80 +#define EMP_LAST 0x40 +static void hdmitx_set_emp_pkt(unsigned char *data, unsigned int type, + unsigned int size) { unsigned int number; + unsigned int remainder; unsigned char *virt_ptr; unsigned char *virt_ptr_align32bit; unsigned long phys_ptr; unsigned int i; struct hdmitx_dev *hdev = &hdmitx_device; -/*******this data is used to test*********/ - unsigned char EMP[64] = {0x81, 0x01, 0x18, 0x57, - 0x03, 0x0c, 0x30, 0x0, 0x0, 0x0}; - number = 2; + unsigned int DS_Type = 0; + unsigned char AFR = 0; + unsigned char VFR = 0; + unsigned char Sync = 0; + unsigned char New = 0; + unsigned char End = 0; + unsigned int Organzation_ID = 0; + unsigned int Data_Set_Tag = 0; + unsigned int Data_Set_Lemgth = 0; -/************************************/ if (hdmitx_device.chip_type < MESON_CPU_ID_G12A) { pr_info("this chip doesn't support emp function\n"); return; } + + if (!data) { + pr_info("the data is null\n"); + return; + } + if (size <= 21) { + number = 1; + remainder = size; + } else { + number = ((size-21)/28) + 2; + remainder = (size - 21) % 28; + } + virt_ptr = kzalloc(sizeof(unsigned char)*(number + 0x1f), GFP_KERNEL); + if (virt_ptr == NULL) + return; pr_info("emp_pkt virt_ptr: %p\n", virt_ptr); virt_ptr_align32bit = (unsigned char *) ((((unsigned long)virt_ptr) + 0x1f) & (~0x1f)); pr_info("emp_pkt virt_ptr_align32bit: %p\n", virt_ptr_align32bit); - for (i = 0; i < number * 32; i++) - virt_ptr_align32bit[i] = EMP[i]; + memset(virt_ptr_align32bit, 0, sizeof(unsigned char)*(number + 0x1f)); + + switch (type) { + case VENDOR_SPECIFIC_EM_DATA: + break; + case COMPRESS_VIDEO_TRAMSPORT: + break; + case HDR_DYNAMIC_METADATA: + DS_Type = 1; + Sync = 1; + VFR = 1; + AFR = 0; + New = 0x1; /*todo*/ + End = 0x1; /*todo*/ + Organzation_ID = 2; + break; + case VIDEO_TIMING_EXTENDED: + break; + default: + break; + } + + for (i = 0; i < number; i++) { + /*HB[0]-[2]*/ + virt_ptr_align32bit[i * 32 + 0] = 0x7F; + if (i == 0) + virt_ptr_align32bit[i * 32 + 1] |= EMP_FIRST; + if (i == number) + virt_ptr_align32bit[i * 32 + 1] |= EMP_LAST; + virt_ptr_align32bit[i * 32 + 2] = number; + /*PB[0]-[6]*/ + if (i == 0) { + virt_ptr_align32bit[3] = (New << 7) | (End << 6) | + (DS_Type << 4) | (AFR << 3) | + (VFR << 2) | (Sync << 1); + virt_ptr_align32bit[4] = 0;/*Rsvd*/ + virt_ptr_align32bit[5] = Organzation_ID; + virt_ptr_align32bit[6] = (Data_Set_Tag >> 8) & 0xFF; + virt_ptr_align32bit[7] = Data_Set_Tag & 0xFF; + virt_ptr_align32bit[8] = (Data_Set_Lemgth >> 8) + & 0xFF; + virt_ptr_align32bit[9] = Data_Set_Lemgth & 0xFF; + } + if (number == 1) { + memcpy(&virt_ptr_align32bit[10], &data[0], + sizeof(unsigned char) * remainder); + } else { + if ((i == 0)) { + /*MD: first package need PB[7]-[27]*/ + memcpy(&virt_ptr_align32bit[10], &data[0], + sizeof(unsigned char) * 21); + } else if (i != number) { + /*MD: following package need PB[0]-[27]*/ + memcpy(&virt_ptr_align32bit[i * 32 + 10], + &data[(i - 1) * 28 + 21], + sizeof(unsigned char) * 28); + } else { + /*MD: the last package need PB[0] to end */ + memcpy(&virt_ptr_align32bit[0], + &data[(i - 1) * 28 + 21], + sizeof(unsigned char) * remainder); + } + } + /*PB[28]*/ + virt_ptr_align32bit[i * 32 + 31] = 0; + } phys_ptr = virt_to_phys(virt_ptr_align32bit); pr_info("emp_pkt phys_ptr: %lx\n", phys_ptr); @@ -1760,6 +1909,7 @@ static ssize_t store_config(struct device *dev, { int ret = 0; struct master_display_info_s data = {0}; + struct hdr10plus_para hdr_data = {0x1, 0x2, 0x3}; pr_info("hdmitx: config: %s\n", buf); @@ -1812,7 +1962,9 @@ static ssize_t store_config(struct device *dev, hdmitx_set_vsif_pkt(buf[4] - '0', buf[5] == '1', NULL); else if (strncmp(buf, "emp", 3) == 0) { if (hdmitx_device.chip_type >= MESON_CPU_ID_G12A) - hdmitx_set_emp_pkt(); + hdmitx_set_emp_pkt(NULL, 1, 1); + } else if (strncmp(buf, "hdr10+", 6) == 0) { + hdmitx_set_hdr10plus_pkt(1, &hdr_data); } return count; } @@ -3371,6 +3523,7 @@ static void hdmitx_hpd_plugout_handler(struct work_struct *work) } /*after plugout, DV mode can't be supported*/ hdmitx_set_vsif_pkt(0, 0, NULL); + hdmitx_set_hdr10plus_pkt(0, NULL); hdev->ready = 0; if (hdev->repeater_tx) rx_repeat_hpd_state(0); diff --git a/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c b/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c index 2f79de3..c8abe65 100644 --- a/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c +++ b/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c @@ -2007,6 +2007,13 @@ static void hdmitx_set_packet(int type, unsigned char *DB, unsigned char *HB) hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD4, DB[7]); hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD5, DB[8]); } + /*set hdr 10+ vsif data information*/ + if ((DB[0] == 0x8b) && (DB[1] == 0x84) && (DB[2] == 0x90)) { + for (i = 0; i < 23; i++) + hdmitx_wr_reg(HDMITX_DWC_FC_VSDPAYLOAD1 + i, + DB[4 + i]); + } + /* Enable VSI packet */ hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO0, 1, 3, 1); hdmitx_wr_reg(HDMITX_DWC_FC_DATAUTO1, 0); diff --git a/drivers/amlogic/media/vout/vout_serve/vout2_serve.c b/drivers/amlogic/media/vout/vout_serve/vout2_serve.c index 667c32e..9fa3582 100644 --- a/drivers/amlogic/media/vout/vout_serve/vout2_serve.c +++ b/drivers/amlogic/media/vout/vout_serve/vout2_serve.c @@ -435,6 +435,11 @@ static ssize_t vout2_vinfo_show(struct class *class, } } len += sprintf(buf+len, "\n"); + len += sprintf(buf+len, "hdr10+:\n"); + len += sprintf(buf+len, " ieeeoui: %x\n", + info->hdr_info.hdr10plus_info.ieeeoui); + len += sprintf(buf+len, " application_version: %x\n", + info->hdr_info.hdr10plus_info.application_version); return len; } diff --git a/drivers/amlogic/media/vout/vout_serve/vout_serve.c b/drivers/amlogic/media/vout/vout_serve/vout_serve.c index be91fcf..d45d326 100644 --- a/drivers/amlogic/media/vout/vout_serve/vout_serve.c +++ b/drivers/amlogic/media/vout/vout_serve/vout_serve.c @@ -510,6 +510,11 @@ static ssize_t vout_vinfo_show(struct class *class, } } len += sprintf(buf+len, "\n"); + len += sprintf(buf+len, "hdr10+:\n"); + len += sprintf(buf+len, " ieeeoui: %x\n", + info->hdr_info.hdr10plus_info.ieeeoui); + len += sprintf(buf+len, " application_version: %x\n", + info->hdr_info.hdr10plus_info.application_version); return len; } diff --git a/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h b/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h index 1e4184d..366e204 100644 --- a/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h +++ b/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h @@ -27,7 +27,7 @@ #include /* HDMITX driver version */ -#define HDMITX_VER "20180808" +#define HDMITX_VER "20181019" /* chip type */ #define MESON_CPU_ID_M8B 0 @@ -112,6 +112,7 @@ struct rx_cap { unsigned char hdr_lum_avg; unsigned char hdr_lum_min; struct hdr_dynamic_struct hdr_dynamic_info[4]; + struct hdr10_plus_info hdr10plus_info; unsigned char IDManufacturerName[4]; unsigned char IDProductCode[2]; unsigned char IDSerialNumber[4]; diff --git a/include/linux/amlogic/media/vout/vinfo.h b/include/linux/amlogic/media/vout/vinfo.h index 2033a31..871d9bb 100644 --- a/include/linux/amlogic/media/vout/vinfo.h +++ b/include/linux/amlogic/media/vout/vinfo.h @@ -53,6 +53,12 @@ enum vout_fr_adj_type_e { VOUT_FR_ADJ_MAX, }; +/*emp : extended metadata type*/ +#define VENDOR_SPECIFIC_EM_DATA 0x0 +#define COMPRESS_VIDEO_TRAMSPORT 0x1 +#define HDR_DYNAMIC_METADATA 0x2 +#define VIDEO_TIMING_EXTENDED 0x3 + #define SUPPORT_2020 0x01 /* master_display_info for display device */ @@ -79,6 +85,12 @@ struct hdr_dynamic { unsigned char optional_fields[28]; }; +struct hdr10_plus_info { + uint32_t ieeeoui; + uint8_t length; + uint8_t application_version; +}; + struct hdr_info { /* RX EDID hdr support types */ u32 hdr_support; @@ -91,6 +103,7 @@ struct hdr_info { *is zero instead of inexistence */ struct hdr_dynamic dynamic_info[4]; + struct hdr10_plus_info hdr10plus_info; /*bit7:BT2020RGB bit6:BT2020YCC bit5:BT2020cYCC bit4:adobeRGB*/ /*bit3:adobeYCC601 bit2:sYCC601 bit1:xvYCC709 bit0:xvYCC601*/ u8 colorimetry_support; /* RX EDID colorimetry support types */ @@ -98,6 +111,18 @@ struct hdr_info { u32 lumi_avg; /* RX EDID Lumi Avg value */ u32 lumi_min; /* RX EDID Lumi Min value */ }; +struct hdr10plus_para { + uint8_t application_version; + uint8_t targeted_max_lum; + uint8_t average_maxrgb; + uint8_t distribution_values[9]; + uint8_t num_bezier_curve_anchors; + uint32_t knee_point_x; + uint32_t knee_point_y; + uint8_t bezier_curve_anchors[9]; + uint8_t graphics_overlay_flag; + uint8_t no_delay_flag; +}; enum eotf_type { EOTF_T_NULL = 0, @@ -116,6 +141,7 @@ enum mode_type { }; #define DV_IEEE_OUI 0x00D046 +#define HDR10_PLUS_IEEE_OUI 0x90848B /* Dolby Version VSIF parameter*/ struct dv_vsif_para { @@ -184,7 +210,11 @@ struct vout_device_s { const struct dv_info *dv_info; void (*fresh_tx_hdr_pkt)(struct master_display_info_s *data); void (*fresh_tx_vsif_pkt)(enum eotf_type type, - enum mode_type tunnel_mode, struct dv_vsif_para *data); + enum mode_type tunnel_mode, struct dv_vsif_para *data); + void (*fresh_tx_hdr10plus_pkt)(unsigned int flag, + struct hdr10plus_para *data); + void (*fresh_tx_emp_pkt)(unsigned char *data, unsigned int type, + unsigned int size); }; struct vinfo_base_s { -- 2.7.4