From 9dd987e9d9e195a9f11d6ece30b729f983a67877 Mon Sep 17 00:00:00 2001 From: yao liu Date: Fri, 9 Aug 2019 09:25:08 -0400 Subject: [PATCH] dolby: enable DV output in uboot [2/6] PD#SWPL-392 Problem: transition from uboot to kernel is not smooth Solution: enable DV output in uboot and kernel check if dolby enabled in uboot Verify: G12B/G12A Change-Id: I7f310794cf18a54c15a6f059c460e8dcdf9c25aa Signed-off-by: yao liu --- .../enhancement/amdolby_vision/amdolby_vision.c | 110 +++++++++++++++++++-- .../enhancement/amdolby_vision/amdolby_vision.h | 1 - drivers/amlogic/media/osd/osd_hw.c | 2 - .../media/vout/hdmitx/hdmi_tx_20/hdmi_tx_edid.c | 28 +++++- .../media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c | 3 + drivers/amlogic/media/vout/vout_serve/vout_serve.c | 39 +++++++- .../amlogic/media/vout/hdmi_tx/hdmi_tx_module.h | 1 + include/linux/amlogic/media/vout/vinfo.h | 1 + 8 files changed, 169 insertions(+), 16 deletions(-) diff --git a/drivers/amlogic/media/enhancement/amdolby_vision/amdolby_vision.c b/drivers/amlogic/media/enhancement/amdolby_vision/amdolby_vision.c index 92e5684..c4dc605 100644 --- a/drivers/amlogic/media/enhancement/amdolby_vision/amdolby_vision.c +++ b/drivers/amlogic/media/enhancement/amdolby_vision/amdolby_vision.c @@ -234,6 +234,8 @@ static unsigned int dolby_vision_flags = FLAG_BYPASS_VPP | FLAG_FORCE_CVM; module_param(dolby_vision_flags, uint, 0664); MODULE_PARM_DESC(dolby_vision_flags, "\n dolby_vision_flags\n"); +#define DV_NAME_LEN_MAX 32 + static unsigned int htotal_add = 0x140; static unsigned int vtotal_add = 0x40; static unsigned int vsize_add; @@ -1043,6 +1045,7 @@ static int is_graphics_output_off(void) static bool dolby_vision_on; static bool dolby_vision_core1_on; static bool dolby_vision_wait_on; +static bool dolby_vision_on_in_uboot; static bool dolby_vision_wait_init; static unsigned int frame_count; static struct hdr10_param_s hdr10_param; @@ -3107,7 +3110,7 @@ void enable_dolby_vision(int enable) 0x80200); /* osd rgb to yuv, vpp out yuv to rgb */ VSYNC_WR_DV_REG(VPP_MATRIX_CTRL, 0x81); - pr_dolby_dbg("Dolby Vision TV core turn on\n"); + pr_info("Dolby Vision TV core turn on\n"); } else if (is_meson_txlx_stbmode() || force_stb_mode) { size = 8 * STB_DMA_TBL_SIZE; @@ -3209,7 +3212,7 @@ void enable_dolby_vision(int enable) last_dolby_vision_ll_policy = dolby_vision_ll_policy; #endif - pr_dolby_dbg("Dolby Vision STB cores turn on\n"); + pr_info("Dolby Vision STB cores turn on\n"); } else if (is_meson_g12() || is_meson_tm2_stbmode()) { hdr_osd_off(); hdr_vd1_off(); @@ -3354,7 +3357,7 @@ void enable_dolby_vision(int enable) last_dolby_vision_ll_policy = dolby_vision_ll_policy; #endif - pr_dolby_dbg("Dolby Vision G12a turn on\n"); + pr_info("Dolby Vision G12a turn on\n"); } else { VSYNC_WR_DV_REG(VPP_DOLBY_CTRL, /* cm_datx4_mode */ @@ -3430,7 +3433,7 @@ void enable_dolby_vision(int enable) last_dolby_vision_ll_policy = dolby_vision_ll_policy; #endif - pr_dolby_dbg("Dolby Vision turn on\n"); + pr_info("Dolby Vision turn on\n"); } } else { if (!dolby_vision_core1_on @@ -3650,6 +3653,7 @@ void enable_dolby_vision(int enable) core1_disp_vsize = 0; dolby_vision_on = false; force_reset_core2 = true; + dolby_vision_on_in_uboot = false; dolby_vision_core1_on = false; dolby_vision_wait_on = false; dolby_vision_wait_init = false; @@ -4284,7 +4288,6 @@ static int dolby_vision_policy_process( mode_change = 0; return mode_change; } - if (((src_format == FORMAT_HLG) || (src_format == FORMAT_HDR10PLUS)) && !(dolby_vision_hdr10_policy & 4)) { @@ -4316,7 +4319,7 @@ static int dolby_vision_policy_process( /* TV support DOVI, All -> DOVI */ if (dolby_vision_mode != DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL) { - pr_dolby_dbg("src=%d, dovi output -> DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL\n", + pr_info("src=%d, dovi output -> DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL\n", src_format); *mode = DOLBY_VISION_OUTPUT_MODE_IPT_TUNNEL; mode_change = 1; @@ -4325,7 +4328,7 @@ static int dolby_vision_policy_process( /* TV support HDR, All -> HDR */ if (dolby_vision_mode != DOLBY_VISION_OUTPUT_MODE_HDR10) { - pr_dolby_dbg("src=%d, dovi output -> DOLBY_VISION_OUTPUT_MODE_HDR10\n", + pr_info("src=%d, dovi output -> DOLBY_VISION_OUTPUT_MODE_HDR10\n", src_format); *mode = DOLBY_VISION_OUTPUT_MODE_HDR10; mode_change = 1; @@ -7065,10 +7068,16 @@ int dolby_vision_process(struct vframe_s *vf, u32 display_size, } EXPORT_SYMBOL(dolby_vision_process); +/* when dolby on in uboot, other module cannot get dolby status + * in time through dolby_vision_on due to dolby_vision_on + * is set in register_dv_functions + * Add dolby_vision_on_in_uboot condition for this case. + */ bool is_dolby_vision_on(void) { return dolby_vision_on - || dolby_vision_wait_on; + || dolby_vision_wait_on + || dolby_vision_on_in_uboot; } EXPORT_SYMBOL(is_dolby_vision_on); @@ -7078,7 +7087,6 @@ bool is_dolby_vision_video_on(void) } EXPORT_SYMBOL(is_dolby_vision_video_on); - bool for_dolby_vision_certification(void) { return is_dolby_vision_on() && @@ -7154,6 +7162,21 @@ int register_dv_functions(const struct dolby_vision_func_s *func) unsigned int reg_clk; unsigned int reg_value; struct pq_config_s *pq_config; + const struct vinfo_s *vinfo = get_current_vinfo(); + + /*when dv ko load into kernel, this flag will be disabled + *otherwise it will effect hdr module + */ + if (dolby_vision_on_in_uboot) { + if (is_vinfo_available(vinfo)) { + is_sink_cap_changed(vinfo); + dolby_vision_on = true; + } else + pr_info("sink not available\n"); + dolby_vision_wait_on = false; + dolby_vision_wait_init = false; + dolby_vision_on_in_uboot = 0; + } if ((!p_funcs_stb || !p_funcs_tv) && func) { if (func->control_path && !p_funcs_stb) { @@ -7550,6 +7573,61 @@ static const char dv_mode_str[6][12] = { "SDR8", "BYPASS" }; +unsigned int dolby_vision_check_enable(void) +{ + int dv_mode = 0; + /*check if dovi enable in uboot*/ + if (is_meson_g12()) { + if (dolby_vision_on_in_uboot) { + dolby_vision_enable = 1; + if ((READ_VPP_DV_REG(DOLBY_CORE3_DIAG_CTRL) & 0xff) + == 0x20) { + /*LL YUV422 mode*/ + dv_mode = dv_mode_table[1]; + /*set_dolby_vision_mode(dv_mode);*/ + dolby_vision_mode = dv_mode; + dolby_vision_ll_policy = DOLBY_VISION_LL_YUV422; + pr_info("dovi enable in uboot and mode is LL 422\n"); + } else if ((READ_VPP_DV_REG(DOLBY_CORE3_DIAG_CTRL) + & 0xff) == 0x3) { + /*LL RGB444 mode*/ + dv_mode = dv_mode_table[1]; + /*set_dolby_vision_mode(dv_mode);*/ + dolby_vision_mode = dv_mode; + dolby_vision_ll_policy = DOLBY_VISION_LL_RGB444; + pr_info("dovi enable in uboot and mode is LL RGB\n"); + } else { + if (READ_VPP_DV_REG(DOLBY_CORE3_REG_START + 1) + == 2) { + /*HDR10 mode*/ + dolby_vision_hdr10_policy = 1; + dv_mode = dv_mode_table[3]; + /*set_dolby_vision_mode(dv_mmde);*/ + dolby_vision_mode = dv_mode; + pr_info("dovi enable in uboot and mode is HDR10\n"); + } else if (READ_VPP_DV_REG(DOLBY_CORE3_REG_START + + 1) == 4) { + /*SDR mode*/ + dv_mode = dv_mode_table[4]; + /*set_dolby_vision_mode(dv_mode);*/ + dolby_vision_mode = dv_mode; + pr_info("dovi enable in uboot and mode is SDR\n"); + } else { + /*STANDARD RGB444 mode*/ + dv_mode = dv_mode_table[2]; + /*set_dolby_vision_mode(dv_mode);*/ + dolby_vision_mode = dv_mode; + dolby_vision_ll_policy = + DOLBY_VISION_LL_DISABLE; + pr_info("dovi enable in uboot and mode is DV ST\n"); + } + } + } else + pr_info("dovi disable in uboot\n"); + } + + return 0; +} static ssize_t amdolby_vision_dv_mode_show(struct class *cla, struct class_attribute *attr, char *buf) @@ -7860,6 +7938,7 @@ static int amdolby_vision_probe(struct platform_device *pdev) dolby_vision_init_receiver(pdev); init_waitqueue_head(&devp->dv_queue); pr_info("%s: ok\n", __func__); + dolby_vision_check_enable(); return 0; fail_create_device: @@ -7912,6 +7991,19 @@ static struct platform_driver aml_amdolby_vision_driver = { .remove = __exit_p(amdolby_vision_remove), }; +static int __init get_dolby_uboot_status(char *str) +{ + char uboot_dolby_status[DV_NAME_LEN_MAX] = {0}; + + snprintf(uboot_dolby_status, DV_NAME_LEN_MAX, "%s", str); + pr_info("get_dolby_on: %s\n", uboot_dolby_status); + + if (!strcmp(uboot_dolby_status, "1")) + dolby_vision_on_in_uboot = 1; + return 0; +} +__setup("dolby_vision_on=", get_dolby_uboot_status); + static int __init amdolby_vision_init(void) { pr_info("%s:module init\n", __func__); diff --git a/drivers/amlogic/media/enhancement/amdolby_vision/amdolby_vision.h b/drivers/amlogic/media/enhancement/amdolby_vision/amdolby_vision.h index 75b944404..24c0ec9 100644 --- a/drivers/amlogic/media/enhancement/amdolby_vision/amdolby_vision.h +++ b/drivers/amlogic/media/enhancement/amdolby_vision/amdolby_vision.h @@ -534,7 +534,6 @@ struct dovi_setting_s { uint32_t vout_width; uint32_t vout_height; u8 vsvdb_tbl[32]; - u8 hdrdb_tbl[7]; struct ext_md_s ext_md; uint32_t vsvdb_len; uint32_t vsvdb_changed; diff --git a/drivers/amlogic/media/osd/osd_hw.c b/drivers/amlogic/media/osd/osd_hw.c index 48f7da8..dbe8ffe 100644 --- a/drivers/amlogic/media/osd/osd_hw.c +++ b/drivers/amlogic/media/osd/osd_hw.c @@ -8681,8 +8681,6 @@ static void osd_setting_default_hwc(void) VSYNCOSD_WR_MPEG_REG(VPP_OSD1_IN_SIZE, blend_vsize << 16 | blend_hsize); - VSYNCOSD_WR_MPEG_REG_BITS(DOLBY_PATH_CTRL, - 0x3, 2, 2); } static bool set_old_hwc_freescale(u32 index) 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 020aacc..4755f0e 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 @@ -91,7 +91,23 @@ static unsigned int hdmitx_edid_check_valid_blocks(unsigned char *buf); static void Edid_DTD_parsing(struct rx_cap *pRXCap, unsigned char *data); static void hdmitx_edid_set_default_aud(struct hdmitx_dev *hdev); -static void edid_save_checkvalue(unsigned char *buf, unsigned int block_cnt) +static int xtochar(int num, unsigned char *checksum) +{ + if (((edid_checkvalue[num] >> 4) & 0xf) <= 9) + checksum[0] = ((edid_checkvalue[num] >> 4) & 0xf) + '0'; + else + checksum[0] = ((edid_checkvalue[num] >> 4) & 0xf) - 10 + 'a'; + + if ((edid_checkvalue[num] & 0xf) <= 9) + checksum[1] = (edid_checkvalue[num] & 0xf) + '0'; + else + checksum[1] = (edid_checkvalue[num] & 0xf) - 10 + 'a'; + + return 0; +} + +static void edid_save_checkvalue(unsigned char *buf, unsigned int block_cnt, + struct rx_cap *RXCap) { unsigned int i, length, max; @@ -105,6 +121,12 @@ static void edid_save_checkvalue(unsigned char *buf, unsigned int block_cnt) for (i = 0; i < max; i++) edid_checkvalue[i] = *(buf+(i+1)*128-1); + + RXCap->chksum[0] = '0'; + RXCap->chksum[1] = 'x'; + + for (i = 0; i < 4; i++) + xtochar(i, &RXCap->chksum[2 * i + 2]); } static int Edid_DecodeHeader(struct hdmitx_info *info, unsigned char *buff) @@ -2422,7 +2444,7 @@ int hdmitx_edid_parse(struct hdmitx_dev *hdmitx_device) if ((!pRXCap->AUD_count) && (!pRXCap->ieeeoui)) hdmitx_edid_set_default_aud(hdmitx_device); - edid_save_checkvalue(EDID_buf, BlockCount+1); + edid_save_checkvalue(EDID_buf, BlockCount + 1, pRXCap); i = hdmitx_edid_dump(hdmitx_device, (char *)(hdmitx_device->tmp_buf), HDMI_TMP_BUF_SIZE); @@ -2435,6 +2457,8 @@ int hdmitx_edid_parse(struct hdmitx_dev *hdmitx_device) /* update RX HDR information */ info = get_current_vinfo(); if (info) { + /*update hdmi checksum to vout*/ + memcpy(info->hdmichecksum, pRXCap->chksum, 10); if (!((strncmp(info->name, "480cvbs", 7) == 0) || (strncmp(info->name, "576cvbs", 7) == 0) || (strncmp(info->name, "null", 4) == 0))) { 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 3841aae..fa6aaec 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 @@ -456,6 +456,9 @@ static int set_disp_mode_auto(void) pr_info(SYS "get current mode: %s\n", info->name); + /*update hdmi checksum to vout*/ + memcpy(info->hdmichecksum, hdev->RXCap.chksum, 10); + if (!((strncmp(info->name, "480cvbs", 7) == 0) || (strncmp(info->name, "576cvbs", 7) == 0) || (strncmp(info->name, "null", 4) == 0))) { diff --git a/drivers/amlogic/media/vout/vout_serve/vout_serve.c b/drivers/amlogic/media/vout/vout_serve/vout_serve.c index 5108256..acfbf18 100644 --- a/drivers/amlogic/media/vout/vout_serve/vout_serve.c +++ b/drivers/amlogic/media/vout/vout_serve/vout_serve.c @@ -75,6 +75,14 @@ static char hdmimode[VMODE_NAME_LEN_MAX] = { static char cvbsmode[VMODE_NAME_LEN_MAX] = { 'i', 'n', 'v', 'a', 'l', 'i', 'd', '\0' }; +static char hdmichecksum[VMODE_NAME_LEN_MAX] = { + 'i', 'n', 'v', 'a', 'l', 'i', 'd', 'c', 'r', 'c', '\0' +}; +static char invalidchecksum[VMODE_NAME_LEN_MAX] = { + 'i', 'n', 'v', 'a', 'l', 'i', 'd', 'c', 'r', 'c', '\0' +}; +static char emptychecksum[VMODE_NAME_LEN_MAX] = {0}; + static enum vmode_e last_vmode = VMODE_MAX; static int tvout_monitor_flag = 1; static unsigned int tvout_monitor_timeout_cnt = 20; @@ -881,14 +889,32 @@ static int refresh_tvout_mode(void) enum vmode_e cur_vmode = VMODE_MAX; char cur_mode_str[VMODE_NAME_LEN_MAX]; int hpd_state = 0; + struct vinfo_s *info = get_current_vinfo(); if (tvout_monitor_flag == 0) return 0; hpd_state = vout_get_hpd_state(); if (hpd_state) { - cur_vmode = validate_vmode(hdmimode); - snprintf(cur_mode_str, VMODE_NAME_LEN_MAX, "%s", hdmimode); + /* Vout will check the checksum of EDID of uboot and kernel. + * If checksum is different. Vout will set null to display/mode. + * When systemcontrol bootup, it will set the correct mode and + * colorspace according to current EDID from kernel. + */ + VOUTPR("hdmichecksum [%s], kernel hdmichecksum [%s]\n", + hdmichecksum, info->hdmichecksum); + if ((memcmp(hdmichecksum, info->hdmichecksum, 10)) && + (memcmp(emptychecksum, info->hdmichecksum, 10)) && + (memcmp(invalidchecksum, hdmichecksum, 10))) { + VOUTPR("hdmi crc is diff between uboot and kernel\n"); + cur_vmode = validate_vmode("null"); + snprintf(cur_mode_str, VMODE_NAME_LEN_MAX, "null"); + + } else { + cur_vmode = validate_vmode(hdmimode); + snprintf(cur_mode_str, VMODE_NAME_LEN_MAX, + "%s", hdmimode); + } } else { cur_vmode = validate_vmode(cvbsmode); snprintf(cur_mode_str, VMODE_NAME_LEN_MAX, "%s", cvbsmode); @@ -1195,6 +1221,15 @@ static int __init get_cvbs_mode(char *str) } __setup("cvbsmode=", get_cvbs_mode); +static int __init get_hdmi_checksum(char *str) +{ + snprintf(hdmichecksum, VMODE_NAME_LEN_MAX, "%s", str); + + VOUTPR("get hdmi checksum: %s\n", hdmichecksum); + return 0; +} +__setup("hdmichecksum=", get_hdmi_checksum); + MODULE_AUTHOR("Platform-BJ "); MODULE_DESCRIPTION("VOUT Server Module"); MODULE_LICENSE("GPL"); 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 cacea67..422803b 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 @@ -164,6 +164,7 @@ struct rx_cap { struct raw_block vsd; /*blk0 check sum*/ unsigned char blk0_chksum; + unsigned char chksum[10]; }; struct cts_conftab { diff --git a/include/linux/amlogic/media/vout/vinfo.h b/include/linux/amlogic/media/vout/vinfo.h index 26294cb..82c630d 100644 --- a/include/linux/amlogic/media/vout/vinfo.h +++ b/include/linux/amlogic/media/vout/vinfo.h @@ -268,6 +268,7 @@ struct vinfo_s { u32 video_clk; u32 htotal; u32 vtotal; + unsigned char hdmichecksum[10]; enum vinfo_3d_e info_3d; enum vout_fr_adj_type_e fr_adj_type; enum color_fmt_e viu_color_fmt; -- 2.7.4