diff --git a/drivers/drm/meson_hdmi.c b/drivers/drm/meson_hdmi.c index 4e1c0f602..eef8585ef 100644 --- a/drivers/drm/meson_hdmi.c +++ b/drivers/drm/meson_hdmi.c @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef CONFIG_DEBUG_FS #include @@ -460,16 +461,33 @@ int meson_hdmitx_get_modes(struct drm_connector *connector) int *vrr_list; int *tmp; int num_group = 0; + u64 sequence_id = 0; if (!am_hdmitx) { DRM_ERROR("am_hdmitx is NULL!\n"); return count; } + sequence_id = am_hdmitx->sequence_id; edid = (struct edid *)hdmitx_get_raw_edid(tx_comm); am_hdmitx->sequence_id = hdmitx_get_hpd_hw_sequence_id(tx_comm); - + /* + * After set mode, hwc will update the connector. + * In order to prevent the edid from being parsed every time, + * the sequence_id judgment is added, and the edid is only parsed + * when the hot_plug time occurs. + */ + if (sequence_id != am_hdmitx->sequence_id) { + DRM_INFO("[%s:%d]:edid parse\n", __func__, __LINE__); + /* step1: SW: edid parse */ + hdmitx_edid_parse(&tx_comm->rxcap, tx_comm->EDID_buf); + hdmitx_common_edid_tracer_post_proc(tx_comm, &tx_comm->rxcap); + /* update the hdr/hdr10+/dv capabilities in the end of parse */ + hdmitx_set_hdr_priority(tx_comm, tx_comm->hdr_priority); + /* step3:SW: update ced status */ + hdmitx_common_notify_ced_status(tx_comm); + } drm_connector_update_edid_property(connector, edid); vrr_list = kcalloc(MAX_VRR_GROUP_VIC_NUM, sizeof(int), GFP_KERNEL); diff --git a/drivers/media/vout/hdmitx20/hdmi_tx_main.c b/drivers/media/vout/hdmitx20/hdmi_tx_main.c index d61f7ee09..dc9f645e1 100644 --- a/drivers/media/vout/hdmitx20/hdmi_tx_main.c +++ b/drivers/media/vout/hdmitx20/hdmi_tx_main.c @@ -3121,6 +3121,20 @@ static DEVICE_ATTR_RO(clkmsr); static DEVICE_ATTR_RO(hdcp22_stopauth); static DEVICE_ATTR_WO(reset_tv_hdcp); +static void hdmitx20_bootup_update_vinfo(struct hdmitx_dev *hdev) +{ + struct hdmitx_common *tx_comm = &hdev->tx_comm; + + edidinfo_attach_to_vinfo(tx_comm); + update_vinfo_from_formatpara(tx_comm); + + /* Should be started at end of output */ + if (hdev->tx_comm.cedst_en) { + cancel_delayed_work(&hdev->tx_comm.work_cedst); + queue_delayed_work(hdev->tx_comm.cedst_wq, &hdev->tx_comm.work_cedst, 0); + } +} + static int hdmitx20_enable_mode(struct hdmitx_common *tx_comm, struct hdmi_format_para *para) { int ret; @@ -3136,24 +3150,11 @@ static int hdmitx20_enable_mode(struct hdmitx_common *tx_comm, struct hdmi_forma static int hdmitx20_init_uboot_mode(enum vmode_e mode) { - struct hdmitx_dev *hdev = get_hdmitx_device(); - - HDMITX_INFO("%s[%d]\n", __func__, __LINE__); - - if (!(mode & VMODE_INIT_BIT_MASK)) { + if (!(mode & VMODE_INIT_BIT_MASK)) HDMITX_ERROR("warning, echo /sys/class/display/mode is disabled\n"); - } else { + else HDMITX_INFO("alread display in uboot\n"); - mutex_lock(&hdev->tx_comm.hdmimode_mutex); - edidinfo_attach_to_vinfo(&hdev->tx_comm); - update_vinfo_from_formatpara(&hdev->tx_comm); - mutex_unlock(&hdev->tx_comm.hdmimode_mutex); - /* Should be started at end of output */ - if (hdev->tx_comm.cedst_en) { - cancel_delayed_work(&hdev->tx_comm.work_cedst); - queue_delayed_work(hdev->tx_comm.cedst_wq, &hdev->tx_comm.work_cedst, 0); - } - } + return 0; } @@ -3214,12 +3215,20 @@ static void hdmitx_cedst_process(struct work_struct *work) queue_delayed_work(tx_comm->cedst_wq, &tx_comm->work_cedst, HZ); } -static void hdmitx_process_plugin(struct hdmitx_dev *hdev, bool set_audio) +static void hdmitx_bootup_process_plugin(struct hdmitx_dev *hdev, bool set_audio) { struct vinfo_s *info = NULL; /* step1: SW: EDID read/parse, notify client modules */ - hdmitx_plugin_common_work(&hdev->tx_comm); + hdmitx_bootup_plugin_work(&hdev->tx_comm); + + /* + * During the kernel startup process, the HDR/DV module will use + * vinfo information, it needs to attach vinfo after the EDID is + * parsed and before the HDR/DV module is enabled. + * so do as hdmitx_common_post_enable_mode() + */ + hdmitx20_bootup_update_vinfo(hdev); /* TODO: need remove/optimised, keep it temporarily */ if (set_audio) { @@ -3229,7 +3238,35 @@ static void hdmitx_process_plugin(struct hdmitx_dev *hdev, bool set_audio) } /* step2: SW: notify client modules and update uevent state */ - hdmitx_common_notify_hpd_status(&hdev->tx_comm, false); + hdmitx_bootup_notify_hpd_status(&hdev->tx_comm, false); +} + +static void hdmitx_process_plugin(struct hdmitx_dev *hdev) +{ + struct hdmitx_common *tx_comm = &hdev->tx_comm; + int i; + unsigned char cta_block_count; + u8 *edid_buf = tx_comm->EDID_buf; + u8 edid_check = 0; + unsigned long flags = 0; + + /* step1: SW: EDID read */ + hdmitx_plugin_common_work(tx_comm); + + /* step2: SW: update cec phy addr and audio data block */ + spin_lock_irqsave(&tx_comm->edid_spinlock, flags); + hdmitx_edid_rxcap_clear(&tx_comm->rxcap); + hdmitx_cec_phy_addr_parse(&tx_comm->rxcap.vsdb_phy_addr, edid_buf); + edid_check = tx_comm->rxcap.edid_check; + cta_block_count = hdmitx_edid_get_cta_block_count(edid_buf); + for (i = 1; i <= cta_block_count; i++) { + if (edid_buf[i * 0x80] == 0x02 || edid_check & 0x01) + hdmitx_edid_audio_block_parse(&tx_comm->rxcap, edid_buf); + } + spin_unlock_irqrestore(&tx_comm->edid_spinlock, flags); + + /* step3: SW: notify client modules and update uevent state */ + hdmitx_common_notify_hpd_status(tx_comm, false); } /* @@ -3243,7 +3280,7 @@ static void hdmitx_bootup_plugin_handler(struct hdmitx_dev *hdev) { if (hdev->tx_comm.fmt_para.tmds_clk_div40) hdmitx_hw_cntl_ddc(&hdev->tx_hw.base, DDC_SCDC_DIV40_SCRAMB, 1); - hdmitx_process_plugin(hdev, hdev->tx_comm.ready); + hdmitx_bootup_process_plugin(hdev, hdev->tx_comm.ready); } static void hdmitx_hpd_plugin_irq_handler(struct work_struct *work) @@ -3274,8 +3311,8 @@ static void hdmitx_hpd_plugin_irq_handler(struct work_struct *work) mutex_unlock(&hdev->tx_comm.hdmimode_mutex); return; } - HDMITX_INFO("hpd_high\n"); - hdmitx_process_plugin(hdev, false); + HDMITX_INFO(SYS "hpd_high\n"); + hdmitx_process_plugin(hdev); mutex_unlock(&hdev->tx_comm.hdmimode_mutex); @@ -3816,7 +3853,7 @@ static int amhdmitx_probe(struct platform_device *pdev) struct hdmitx_event_mgr *tx_uevent_mgr; bool hpd_state; - HDMITX_DEBUG("amhdmitx_probe_start\n"); + HDMITX_INFO("amhdmitx_probe_start\n"); hdev = devm_kzalloc(device, sizeof(*hdev), GFP_KERNEL); if (!hdev) @@ -3999,6 +4036,7 @@ static int amhdmitx_probe(struct platform_device *pdev) hdmitx_bootup_plugin_handler(hdev); else hdmitx_bootup_plugout_handler(hdev); + /* after unlock, now can take actions of bottom half of hpd irq */ mutex_unlock(&hdev->tx_comm.hdmimode_mutex); /* notify to drm hdmi */ @@ -4008,7 +4046,8 @@ static int amhdmitx_probe(struct platform_device *pdev) hdmitx_sysfs_common_create(dev, &hdev->tx_comm, &hdev->tx_hw.base); hdev->hdmi_init = 1; - HDMITX_DEBUG("amhdmitx_probe_end\n"); + HDMITX_INFO("amhdmitx_probe_end\n"); + return r; } diff --git a/drivers/media/vout/hdmitx21/hdmi_tx_main.c b/drivers/media/vout/hdmitx21/hdmi_tx_main.c index d3fcfede4..4e02d9fd0 100644 --- a/drivers/media/vout/hdmitx21/hdmi_tx_main.c +++ b/drivers/media/vout/hdmitx21/hdmi_tx_main.c @@ -3881,6 +3881,40 @@ static bool is_frl_ready(struct hdmitx_dev *hdev) } } +static void hdmitx21_bootup_update_vinfo(struct hdmitx_dev *hdev) +{ + struct vinfo_s *vinfo = NULL; + struct hdmitx_common *tx_comm = &hdev->tx_comm; + + edidinfo_attach_to_vinfo(tx_comm); + update_vinfo_from_formatpara(tx_comm); + vinfo = hdmitx_get_current_vinfo(NULL); + if (vinfo) { + vinfo->cur_enc_ppc = 1; + if (hdev->frl_rate > FRL_NONE) + vinfo->cur_enc_ppc = 4; +#ifdef CONFIG_AMLOGIC_DSC + /* can also use if (hdev->dsc_en) */ + if (get_dsc_en()) { + if (hdev->tx_comm.fmt_para.cs == HDMI_COLORSPACE_RGB) + vinfo->vpp_post_out_color_fmt = 1; + else + vinfo->vpp_post_out_color_fmt = 0; + } else { + vinfo->vpp_post_out_color_fmt = 0; + } +#endif + HDMITX_INFO("vinfo: set cur_enc_ppc as %d, vpp color: %d\n", + vinfo->cur_enc_ppc, vinfo->vpp_post_out_color_fmt); + } + + /* started after output setting done */ + if (hdev->tx_comm.cedst_en) { + cancel_delayed_work(&hdev->tx_comm.work_cedst); + queue_delayed_work(hdev->tx_comm.cedst_wq, &hdev->tx_comm.work_cedst, 0); + } +} + static int hdmitx21_enable_mode(struct hdmitx_common *tx_comm, struct hdmi_format_para *para) { int ret; @@ -3959,48 +3993,11 @@ static int hdmitx21_disable_mode(struct hdmitx_common *tx_comm, struct hdmi_form static int hdmitx21_init_uboot_mode(enum vmode_e mode) { - struct vinfo_s *vinfo = NULL; - struct hdmitx_dev *hdev = get_hdmitx21_device(); - -#ifndef CONFIG_AMLOGIC_ZAPPER_CUT - hdmitx_register_vrr(hdev); -#endif - - if (!(mode & VMODE_INIT_BIT_MASK)) { + if (!(mode & VMODE_INIT_BIT_MASK)) HDMITX_ERROR("warning, echo /sys/class/display/mode is disabled\n"); - } else { + else HDMITX_INFO("already display in uboot\n"); - mutex_lock(&hdev->tx_comm.hdmimode_mutex); - if (!is_frl_ready(hdev)) - hdev->tx_comm.ready = 0; - edidinfo_attach_to_vinfo(&hdev->tx_comm); - update_vinfo_from_formatpara(&hdev->tx_comm); - vinfo = get_current_vinfo(); - if (vinfo) { - vinfo->cur_enc_ppc = 1; - if (hdev->frl_rate > FRL_NONE) - vinfo->cur_enc_ppc = 4; -#ifdef CONFIG_AMLOGIC_DSC - /* can also use if (hdev->dsc_en) */ - if (get_dsc_en()) { - if (hdev->tx_comm.fmt_para.cs == HDMI_COLORSPACE_RGB) - vinfo->vpp_post_out_color_fmt = 1; - else - vinfo->vpp_post_out_color_fmt = 0; - } else { - vinfo->vpp_post_out_color_fmt = 0; - } -#endif - HDMITX_INFO("vinfo: set cur_enc_ppc as %d, vpp color: %d\n", - vinfo->cur_enc_ppc, vinfo->vpp_post_out_color_fmt); - } - mutex_unlock(&hdev->tx_comm.hdmimode_mutex); - /* started after output setting done */ - if (hdev->tx_comm.cedst_en) { - cancel_delayed_work(&hdev->tx_comm.work_cedst); - queue_delayed_work(hdev->tx_comm.cedst_wq, &hdev->tx_comm.work_cedst, 0); - } - } + return 0; } @@ -4062,12 +4059,19 @@ static void hdmitx_cedst_process(struct work_struct *work) queue_delayed_work(tx_comm->cedst_wq, &tx_comm->work_cedst, HZ); } -static void hdmitx_process_plugin(struct hdmitx_dev *hdev, bool set_audio) +static void hdmitx_bootup_process_plugin(struct hdmitx_dev *hdev, bool set_audio) { struct vinfo_s *info = NULL; /* step1: SW: EDID read/parse, notify client modules */ - hdmitx_plugin_common_work(&hdev->tx_comm); + hdmitx_bootup_plugin_work(&hdev->tx_comm); + + /* During the kernel startup process, the HDR/DV module will use + * vinfo information, it needs to attach vinfo after the EDID is + * parsed and before the HDR/DV module is enabled. + * so do as hdmitx_common_post_enable_mode() + */ + hdmitx21_bootup_update_vinfo(hdev); /* only bootup plugin will set audio mode, other plugin will not do that */ if (set_audio) { @@ -4077,7 +4081,35 @@ static void hdmitx_process_plugin(struct hdmitx_dev *hdev, bool set_audio) } /* step2: SW: notify client modules and update uevent state */ - hdmitx_common_notify_hpd_status(&hdev->tx_comm, false); + hdmitx_bootup_notify_hpd_status(&hdev->tx_comm, false); +} + +static void hdmitx_process_plugin(struct hdmitx_dev *hdev) +{ + struct hdmitx_common *tx_comm = &hdev->tx_comm; + int i; + unsigned char cta_block_count; + unsigned char *edid_buf = tx_comm->EDID_buf; + unsigned char edid_check = 0; + unsigned long flags = 0; + + /* step1: SW: EDID read */ + hdmitx_plugin_common_work(tx_comm); + + /* step2: update cec phy addr and audio data block */ + spin_lock_irqsave(&tx_comm->edid_spinlock, flags); + hdmitx_edid_rxcap_clear(&tx_comm->rxcap); + hdmitx_cec_phy_addr_parse(&tx_comm->rxcap.vsdb_phy_addr, tx_comm->EDID_buf); + edid_check = tx_comm->rxcap.edid_check; + cta_block_count = hdmitx_edid_get_cta_block_count(edid_buf); + for (i = 1; i <= cta_block_count; i++) { + if (edid_buf[i * 0x80] == 0x02 || edid_check & 0x01) + hdmitx_edid_audio_block_parse(&tx_comm->rxcap, edid_buf); + } + spin_unlock_irqrestore(&tx_comm->edid_spinlock, flags); + + /* step3: SW: notify client modules and update uevent state */ + hdmitx_common_notify_hpd_status(tx_comm, false); } /* @@ -4098,7 +4130,7 @@ static void hdmitx_bootup_plugin_handler(struct hdmitx_dev *hdev) if (!is_frl_ready(hdev)) hdev->tx_comm.ready = 0; } - hdmitx_process_plugin(hdev, hdev->tx_comm.ready); + hdmitx_bootup_process_plugin(hdev, hdev->tx_comm.ready); } static void hdmitx_hpd_plugin_irq_handler(struct work_struct *work) @@ -4131,7 +4163,7 @@ static void hdmitx_hpd_plugin_irq_handler(struct work_struct *work) return; } HDMITX_INFO(SYS "hpd_high\n"); - hdmitx_process_plugin(hdev, false); + hdmitx_process_plugin(hdev); mutex_unlock(&hdev->tx_comm.hdmimode_mutex); @@ -4302,7 +4334,6 @@ static int amhdmitx21_device_init(struct hdmitx_dev *hdev) hdev->hdtx_dev = NULL; - hdev->tx_comm.rxcap.physical_addr = 0xffff; hdev->tx_comm.hdmi_last_hdr_mode = 0; hdev->tx_comm.hdmi_current_hdr_mode = 0; @@ -5003,6 +5034,10 @@ static int amhdmitx_probe(struct platform_device *pdev) /* load init hdr state for HW info */ hdmitx_hdr_state_init(&hdev->tx_comm); +#ifndef CONFIG_AMLOGIC_ZAPPER_CUT + hdmitx_register_vrr(hdev); +#endif + /* after unlock, now can take actions of bottom half of hpd irq */ mutex_unlock(&hdev->tx_comm.hdmimode_mutex); /* notify to drm hdmi */ diff --git a/drivers/media/vout/hdmitx_common/hdmitx_common.c b/drivers/media/vout/hdmitx_common/hdmitx_common.c index edaeda27a..3243a6d38 100644 --- a/drivers/media/vout/hdmitx_common/hdmitx_common.c +++ b/drivers/media/vout/hdmitx_common/hdmitx_common.c @@ -57,7 +57,6 @@ int hdmitx_common_init(struct hdmitx_common *tx_comm, struct hdmitx_hw_common *h tx_comm->tx_hw->hdmi_tx_cap.dsc_policy = boot_param->dsc_policy; hw_comm->hdcp_repeater_en = 0; - tx_comm->rxcap.physical_addr = 0xffff; tx_comm->debug_param.avmute_frame = 0; hdmitx_format_para_reset(&tx_comm->fmt_para); @@ -593,15 +592,23 @@ int hdmitx_common_parse_vic_in_edid(struct hdmitx_common *tx_comm, const char *m } EXPORT_SYMBOL(hdmitx_common_parse_vic_in_edid); -int hdmitx_common_notify_hpd_status(struct hdmitx_common *tx_comm, bool force_uevent) +int hdmitx_common_notify_ced_status(struct hdmitx_common *tx_comm) { - if (!tx_comm->suspend_flag) { + /* if cedst_en is 1, ced detection will be enabled in hdmitx_common_post_enable_mode */ + if (tx_comm->cedst_policy == 1) + tx_comm->cedst_en = !!tx_comm->rxcap.scdc_present; + + return 0; +} +EXPORT_SYMBOL(hdmitx_common_notify_ced_status); + +int hdmitx_bootup_notify_hpd_status(struct hdmitx_common *tx_comm, bool force_uevent) +{ + if (!tx_comm->suspend_flag) /* notify to userspace by uevent */ hdmitx_event_mgr_send_uevent(tx_comm->event_mgr, - HDMITX_HPD_EVENT, tx_comm->hpd_state, force_uevent); - hdmitx_event_mgr_send_uevent(tx_comm->event_mgr, - HDMITX_AUDIO_EVENT, tx_comm->hpd_state, force_uevent); - } else { + HDMITX_HPD_EVENT, tx_comm->hpd_state, force_uevent); + else /* * under early suspend, only update uevent state, not * post to system, in case 1.old android system will @@ -609,10 +616,7 @@ int hdmitx_common_notify_hpd_status(struct hdmitx_common *tx_comm, bool force_ue * start run, increase power consumption */ hdmitx_event_mgr_set_uevent_state(tx_comm->event_mgr, - HDMITX_HPD_EVENT, tx_comm->hpd_state); - hdmitx_event_mgr_set_uevent_state(tx_comm->event_mgr, - HDMITX_AUDIO_EVENT, tx_comm->hpd_state); - } + HDMITX_HPD_EVENT, tx_comm->hpd_state); /* * always notify to other driver module: CEC/RX @@ -627,6 +631,37 @@ int hdmitx_common_notify_hpd_status(struct hdmitx_common *tx_comm, bool force_ue hdmitx_event_mgr_notify(tx_comm->event_mgr, HDMITX_UNPLUG, NULL); return 0; } +EXPORT_SYMBOL(hdmitx_bootup_notify_hpd_status); + +int hdmitx_common_notify_hpd_status(struct hdmitx_common *tx_comm, bool force_uevent) +{ + if (!tx_comm->suspend_flag) + /* notify to userspace by uevent */ + hdmitx_event_mgr_send_uevent(tx_comm->event_mgr, + HDMITX_HPD_EVENT, tx_comm->hpd_state, force_uevent); + else + /* + * under early suspend, only update uevent state, not + * post to system, in case 1.old android system will + * set hdmi mode, 2.audio server and audio_hal will + * start run, increase power consumption + */ + hdmitx_event_mgr_set_uevent_state(tx_comm->event_mgr, + HDMITX_HPD_EVENT, tx_comm->hpd_state); + /* + * always notify to other driver module: CEC/RX + * CEC/RX side will decide to update HPD/EDID or + * not by product type + */ + /* if (tx_comm->hdmi_repeater == 1) { */ + if (tx_comm->hpd_state) + hdmitx_event_mgr_notify(tx_comm->event_mgr, HDMITX_PLUG, tx_comm->EDID_buf); + else + hdmitx_event_mgr_notify(tx_comm->event_mgr, HDMITX_UNPLUG, NULL); + + return 0; +} +EXPORT_SYMBOL(hdmitx_common_notify_hpd_status); bool hdmitx_hdr_en(struct hdmitx_hw_common *tx_hw) { @@ -765,11 +800,11 @@ int hdmitx_common_edid_tracer_post_proc(struct hdmitx_common *tx_comm, struct rx return 0; } +EXPORT_SYMBOL(hdmitx_common_edid_tracer_post_proc); int hdmitx_common_get_edid(struct hdmitx_common *tx_comm) { struct hdmitx_hw_common *tx_hw_base = tx_comm->tx_hw; - unsigned long flags = 0; if (tx_comm->forced_edid) { HDMITX_INFO("using fixed edid\n"); @@ -811,16 +846,6 @@ int hdmitx_common_get_edid(struct hdmitx_common *tx_comm) } } - spin_lock_irqsave(&tx_comm->edid_spinlock, flags); - hdmitx_edid_rxcap_clear(&tx_comm->rxcap); - hdmitx_edid_parse(&tx_comm->rxcap, tx_comm->EDID_buf); - hdmitx_common_edid_tracer_post_proc(tx_comm, &tx_comm->rxcap); - - /* update the hdr/hdr10+/dv capabilities in the end of parse */ - hdmitx_set_hdr_priority(tx_comm, tx_comm->hdr_priority); - - spin_unlock_irqrestore(&tx_comm->edid_spinlock, flags); - /* * notify phy addr to rx/cec: * rx/cec currently do not use the phy addr of below diff --git a/drivers/media/vout/hdmitx_common/hdmitx_edid_parse.c b/drivers/media/vout/hdmitx_common/hdmitx_edid_parse.c index 91532ebb3..fdd368751 100644 --- a/drivers/media/vout/hdmitx_common/hdmitx_edid_parse.c +++ b/drivers/media/vout/hdmitx_common/hdmitx_edid_parse.c @@ -66,16 +66,32 @@ const struct hdmi_timing *hdmitx_mode_match_timing_name(const char *name); static void edid_dtd_parsing(struct rx_cap *prxcap, unsigned char *data); static void hdmitx_edid_set_default_aud(struct rx_cap *prxcap); -static void phy_addr_clear(struct vsdb_phyaddr *vsdb_phy_addr) +static u16 hdmitx_cec_get_edid_phys_addr(const u8 *edid, unsigned int size) { + unsigned int loc = cec_get_edid_spa_location(edid, size); + + if (loc == 0) + return 0xffff; + return (edid[loc] << 8) | edid[loc + 1]; +} + +void hdmitx_cec_phy_addr_parse(struct vsdb_phyaddr *vsdb_phy_addr, const u8 *edid_buf) +{ + u16 pa = 0xffff; + if (!vsdb_phy_addr) return; - vsdb_phy_addr->a = 0; - vsdb_phy_addr->b = 0; - vsdb_phy_addr->c = 0; - vsdb_phy_addr->d = 0; - vsdb_phy_addr->valid = 0; + if (edid_buf && edid_buf[0x7e]) { + pa = hdmitx_cec_get_edid_phys_addr((const u8 *)edid_buf, + 128 * (edid_buf[0x7e] + 1)); + vsdb_phy_addr->a = (pa >> 12) & 0xf; + vsdb_phy_addr->b = (pa >> 8) & 0xf; + vsdb_phy_addr->c = (pa >> 4) & 0xf; + vsdb_phy_addr->d = (pa >> 0) & 0xf; + if (pa != 0xffff) + vsdb_phy_addr->valid = 1; + } } static bool hdmitx_edid_header_invalid(u8 edid_check, const u8 *buf) @@ -99,7 +115,7 @@ static bool hdmitx_edid_header_invalid(u8 edid_check, const u8 *buf) } /* return the blocks of extension CTA */ -static unsigned char hdmitx_edid_get_cta_block_count(const u8 *edid_buf) +unsigned char hdmitx_edid_get_cta_block_count(const u8 *edid_buf) { unsigned char cta_block_count = 0; @@ -644,39 +660,6 @@ static void edid_parseceatiming(struct rx_cap *prxcap, } } -static struct vsdb_phyaddr vsdb_local = {0}; -int get_vsdb_phy_addr(struct vsdb_phyaddr *vsdb) -{ - if (!vsdb) - return -1; - - vsdb = &vsdb_local; - return vsdb->valid; -} - -static void set_vsdb_phy_addr(struct rx_cap *prxcap, - unsigned char *edid_offset) -{ - int phy_addr; - struct vsdb_phyaddr *vsdb; - - if (!prxcap || !edid_offset) - return; - vsdb = &prxcap->vsdb_phy_addr; - vsdb->a = (edid_offset[0] >> 4) & 0xf; - vsdb->b = (edid_offset[0] >> 0) & 0xf; - vsdb->c = (edid_offset[1] >> 4) & 0xf; - vsdb->d = (edid_offset[1] >> 0) & 0xf; - vsdb_local = *vsdb; - vsdb->valid = 1; - - phy_addr = ((vsdb->a & 0xf) << 12) | - ((vsdb->b & 0xf) << 8) | - ((vsdb->c & 0xf) << 4) | - ((vsdb->d & 0xf) << 0); - prxcap->physical_addr = phy_addr; -} - static void set_vsdb_dc_cap(struct rx_cap *prxcap) { if (!prxcap) @@ -1483,7 +1466,6 @@ static void hdmitx_edid_parse_hdmi14(struct rx_cap *prxcap, return; prxcap->ieeeoui = HDMI_IEEE_OUI; - set_vsdb_phy_addr(prxcap, &block_buf[offset + 3]); prxcap->ColorDeepSupport = (count > 5) ? block_buf[offset + 5] : 0; set_vsdb_dc_cap(prxcap); @@ -1869,15 +1851,80 @@ static void _store_vics(struct rx_cap *prxcap, u8 vic_dat) } } -static int hdmitx_edid_cta_block_parse(struct rx_cap *prxcap, u8 *block_buf) +int hdmitx_edid_audio_block_parse(struct rx_cap *prxcap, u8 *block_buf) { u8 offset, end; u8 count; u8 tag; int i, tmp, idx; - u8 *vfpdb_offset = NULL; u32 aud_flag = 0; + if (!prxcap || !block_buf) + return -1; + + /* CTA Block */ + block_buf += 0x80; + /* CEA description */ + end = block_buf[2]; + /* Initialize SVD_VIC used for SVD storage in the video data block */ + if (end > 127) + return 0; + + if (block_buf[1] <= 2) { + /* skip below for loop */ + goto next; + } + + /* this loop should be parsing when revision number is larger than 2 */ + for (offset = 4 ; offset < end ; ) { + tag = block_buf[offset] >> 5; + count = block_buf[offset] & 0x1f; + switch (tag) { + case HDMI_EDID_BLOCK_TYPE_AUDIO: + aud_flag = 1; + tmp = count / 3; + idx = prxcap->AUD_count; + prxcap->AUD_count += tmp; + offset++; + for (i = 0; i < tmp; i++) { + prxcap->RxAudioCap[idx + i].audio_format_code = + (block_buf[offset + i * 3] >> 3) & 0xf; + prxcap->RxAudioCap[idx + i].channel_num_max = + block_buf[offset + i * 3] & 0x7; + prxcap->RxAudioCap[idx + i].freq_cc = + block_buf[offset + i * 3 + 1] & 0x7f; + prxcap->RxAudioCap[idx + i].cc3 = + block_buf[offset + i * 3 + 2]; + } + offset += count; + break; + default: + offset++; + offset += count; + break; + } + } +next: + if (aud_flag == 0) + hdmitx_edid_set_default_aud(prxcap); + + /* dtds in extended blocks */ + i = 0; + offset = block_buf[2] + i * 18; + for ( ; (offset + 18) < 0x7f; i++) + offset += 18; + + return 0; +} + +static int hdmitx_edid_cta_block_parse(struct rx_cap *prxcap, u8 *block_buf) +{ + u8 offset, end; + u8 count; + u8 tag; + int i; + u8 *vfpdb_offset = NULL; + if (!prxcap || !block_buf) return -1; @@ -1911,25 +1958,6 @@ static int hdmitx_edid_cta_block_parse(struct rx_cap *prxcap, u8 *block_buf) tag = block_buf[offset] >> 5; count = block_buf[offset] & 0x1f; switch (tag) { - case HDMI_EDID_BLOCK_TYPE_AUDIO: - aud_flag = 1; - tmp = count / 3; - idx = prxcap->AUD_count; - prxcap->AUD_count += tmp; - offset++; - for (i = 0; i < tmp; i++) { - prxcap->RxAudioCap[idx + i].audio_format_code = - (block_buf[offset + i * 3] >> 3) & 0xf; - prxcap->RxAudioCap[idx + i].channel_num_max = - block_buf[offset + i * 3] & 0x7; - prxcap->RxAudioCap[idx + i].freq_cc = - block_buf[offset + i * 3 + 1] & 0x7f; - prxcap->RxAudioCap[idx + i].cc3 = - block_buf[offset + i * 3 + 2]; - } - offset += count; - break; - case HDMI_EDID_BLOCK_TYPE_VIDEO: offset++; for (i = 0; i < count ; i++) { @@ -2047,6 +2075,8 @@ static int hdmitx_edid_cta_block_parse(struct rx_cap *prxcap, u8 *block_buf) break; default: + offset++; + offset += count; break; } } @@ -2068,9 +2098,6 @@ next: edid_parsedrmsb(prxcap, drm_data); } - if (aud_flag == 0) - hdmitx_edid_set_default_aud(prxcap); - edid_y420cmdb_postprocess(prxcap); /* dtds in extended blocks */ @@ -2565,7 +2592,6 @@ static void edid_set_fallback_mode(struct rx_cap *prxcap) phyaddr->c = 0xf; phyaddr->d = 0xf; phyaddr->valid = 0; - prxcap->physical_addr = 0xffff; /* 165MHZ / 5 */ prxcap->Max_TMDS_Clock1 = DEFAULT_MAX_TMDS_CLK; @@ -2829,11 +2855,9 @@ int hdmitx_edid_parse(struct rx_cap *prxcap, u8 *edid_buf) if (edid_zero_data(edid_buf) || prxcap->VIC_count == 0) hdmitx_edid_set_default_vic(prxcap); - if (prxcap->ieeeoui != HDMI_IEEE_OUI) - prxcap->physical_addr = 0xffff; - return 0; } +EXPORT_SYMBOL(hdmitx_edid_parse); void hdmitx_edid_buffer_clear(u8 *edid_buf, int size) { @@ -2866,7 +2890,6 @@ void hdmitx_edid_rxcap_clear(struct rx_cap *prxcap) hdmitx_edid_set_default_aud(prxcap); rx_set_hdr_lumi(&tmp[0], 2); /* rx_set_receiver_edid(&tmp[0], 2); */ - phy_addr_clear(&prxcap->vsdb_phy_addr); } /* @@ -2986,6 +3009,7 @@ int hdmitx_edid_print_sink_cap(const struct rx_cap *prxcap, * pos += snprintf(buffer + pos, buffer_len - pos, * "EDID block number: 0x%x\n", tx_comm->EDID_buf[0x7e]); */ + pos += snprintf(buffer + pos, buffer_len - pos, "Source Physical Address[a.b.c.d]: %x.%x.%x.%x\n", prxcap->vsdb_phy_addr.a, diff --git a/drivers/media/vout/hdmitx_common/hdmitx_mode_set.c b/drivers/media/vout/hdmitx_common/hdmitx_mode_set.c index 6a67858f0..9f40a6228 100644 --- a/drivers/media/vout/hdmitx_common/hdmitx_mode_set.c +++ b/drivers/media/vout/hdmitx_common/hdmitx_mode_set.c @@ -155,17 +155,18 @@ void update_vinfo_from_formatpara(struct hdmitx_common *tx_comm) struct vinfo_s *vinfo = &tx_comm->hdmitx_vinfo; struct hdmi_format_para *fmtpara = &tx_comm->fmt_para; - /*update vinfo for out device.*/ + /* update vinfo for out device */ calc_vinfo_from_hdmi_timing(&fmtpara->timing, vinfo); - /*vinfo->info_3d = NON_3D; - *if (hdev->flag_3dfp) - * vinfo->info_3d = FP_3D; - *if (hdev->flag_3dtb) - * vinfo->info_3d = TB_3D; - *if (hdev->flag_3dss) - * vinfo->info_3d = SS_3D; + /* + * vinfo->info_3d = NON_3D; + * if (hdev->flag_3dfp) + * vinfo->info_3d = FP_3D; + * if (hdev->flag_3dtb) + * vinfo->info_3d = TB_3D; + * if (hdev->flag_3dss) + * vinfo->info_3d = SS_3D; */ - /*dynamic info, always need set.*/ + /* dynamic info, always need set */ vinfo->cs = fmtpara->cs; vinfo->cd = fmtpara->cd; } @@ -241,7 +242,8 @@ static int hdmitx_common_post_enable_mode(struct hdmitx_common *tx_comm, cancel_delayed_work(&tx_comm->work_cedst); queue_delayed_work(tx_comm->cedst_wq, &tx_comm->work_cedst, 0); } - /* attach vinfo, if hdr_cap and dv_cap change, the HDR/DV module will + /* + * attach vinfo, if hdr_cap and dv_cap change, the HDR/DV module will * call the packet sending function, need to set ready flag to 1 first */ tx_comm->ready = 1; @@ -517,16 +519,8 @@ struct vinfo_s *hdmitx_get_current_vinfo(void *data) static int hdmitx_set_current_vmode(enum vmode_e mode, void *data) { - if (!(mode & VMODE_INIT_BIT_MASK)) { + if (!(mode & VMODE_INIT_BIT_MASK)) HDMITX_INFO("warning, echo /sys/class/display/mode is disabled\n"); - } else { - /* During the kernel startup process, the HDR/DV module will use - * vinfo information, it needs to attach vinfo after the EDID is - * parsed and before the HDR/DV module is enabled. - * so do as hdmitx_common_post_enable_mode() - */ - global_tx_common->ctrl_ops->init_uboot_mode(mode); - } return 0; } @@ -828,6 +822,87 @@ void hdmitx_vout_uninit(void) } } +static void hdmitx_bootup_parse_edid(struct hdmitx_common *tx_comm) +{ + unsigned long flags = 0; + int i; + unsigned char cta_block_count; + unsigned char *edid_buf = tx_comm->EDID_buf; + unsigned char edid_check = 0; + + spin_lock_irqsave(&tx_comm->edid_spinlock, flags); + hdmitx_edid_rxcap_clear(&tx_comm->rxcap); + hdmitx_edid_parse(&tx_comm->rxcap, tx_comm->EDID_buf); + /* update cec phy addr and audio data block */ + hdmitx_cec_phy_addr_parse(&tx_comm->rxcap.vsdb_phy_addr, tx_comm->EDID_buf); + edid_check = tx_comm->rxcap.edid_check; + cta_block_count = hdmitx_edid_get_cta_block_count(edid_buf); + for (i = 1; i <= cta_block_count; i++) { + if (edid_buf[i * 0x80] == 0x02 || edid_check & 0x01) + hdmitx_edid_audio_block_parse(&tx_comm->rxcap, edid_buf); + } + hdmitx_common_edid_tracer_post_proc(tx_comm, &tx_comm->rxcap); + + /* update the hdr/hdr10+/dv capabilities in the end of parse */ + hdmitx_set_hdr_priority(tx_comm, tx_comm->hdr_priority); + + spin_unlock_irqrestore(&tx_comm->edid_spinlock, flags); +} + +/* work for bootup when hpd is high */ +void hdmitx_bootup_plugin_work(struct hdmitx_common *tx_comm) +{ + /* trace event */ + hdmitx_tracer_write_event(tx_comm->tx_tracer, HDMITX_HPD_PLUGIN); + + tx_comm->tx_hw->hw_sequence_id = get_jiffies_64(); + HDMITX_INFO("plugin sequence id: %lld\n", tx_comm->tx_hw->hw_sequence_id); + + /* SW: start rxsense check */ + if (tx_comm->rxsense_policy) { + cancel_delayed_work(&tx_comm->work_rxsense); + queue_delayed_work(tx_comm->rxsense_wq, &tx_comm->work_rxsense, 0); + } + + /* SW/HW: read/parse EDID */ + /* there may be such case: + * hpd rising & hpd level high (0.6S > HZ/2)--> + * plugin handler-->hpd falling & hpd level low(0.05S)--> + * continue plugin handler, EDID read normal, + * post plugin uevent--> + * plugout handler(may be filtered and skipped): + * stop hdcp/clear edid, post plugout uevent--> + * system plugin handle: set hdmi mode/hdcp auth--> + * system plugout handle: set non-hdmi mode(but hdcp is still running)--> + * hpd rising & keep level high-->plugin handler, EDID read abnormal + * as hdcp auth is running and may access DDC when reading EDID. + * so need to disable hdcp auth before EDID reading + */ + if (tx_comm->hdcp_mode != 0) { + HDMITX_INFO("hdcp: %d should not be enabled before signal ready\n", + tx_comm->hdcp_mode); + tx_comm->ctrl_ops->disable_hdcp(tx_comm); + } + + /* read edid */ + hdmitx_common_get_edid(tx_comm); + /* edid parse */ + hdmitx_bootup_parse_edid(tx_comm); + + /* SW: update flags */ + if (tx_comm->cedst_policy == 1) + tx_comm->cedst_en = !!tx_comm->rxcap.scdc_present; + + tx_comm->hpd_state = 1; + tx_comm->already_used = 1; + + /* SW: special for hdcp repeater */ + if (tx_comm->tx_hw->hdcp_repeater_en) + rx_set_repeater_support(1); + + tx_comm->last_hpd_handle_done_stat = HDMI_TX_HPD_PLUGIN; +} + /* common work for plugin/resume, which is done in lock */ void hdmitx_plugin_common_work(struct hdmitx_common *tx_comm) { @@ -866,10 +941,6 @@ void hdmitx_plugin_common_work(struct hdmitx_common *tx_comm) /*read edid*/ hdmitx_common_get_edid(tx_comm); - /* SW: update flags */ - if (tx_comm->cedst_policy == 1) - tx_comm->cedst_en = !!tx_comm->rxcap.scdc_present; - tx_comm->hpd_state = 1; tx_comm->already_used = 1; @@ -930,6 +1001,7 @@ void hdmitx_ext_plugin_handler(void) mutex_lock(&global_tx_common->hdmimode_mutex); hdmitx_common_get_edid(global_tx_common); mutex_unlock(&global_tx_common->hdmimode_mutex); + HDMITX_INFO("read edid by erac\n"); } } EXPORT_SYMBOL(hdmitx_ext_plugin_handler); diff --git a/include/linux/amlogic/media/vout/hdmitx_common/hdmitx_common.h b/include/linux/amlogic/media/vout/hdmitx_common/hdmitx_common.h index 8a9e84e01..a7e1e3104 100644 --- a/include/linux/amlogic/media/vout/hdmitx_common/hdmitx_common.h +++ b/include/linux/amlogic/media/vout/hdmitx_common/hdmitx_common.h @@ -104,7 +104,6 @@ struct hdmitx_common { u32 forced_edid; /* for external loading EDID */ unsigned char EDID_buf[EDID_MAX_BLOCK * 128]; struct rx_cap rxcap; - /****** hdmitx state ******/ /* Normally, after the HPD in or late resume, there will reading EDID, and * notify application to select a hdmi mode output. But during the mode @@ -250,16 +249,20 @@ enum HDMITX_PLATFORM_API_TYPE { int hdmitx_common_attch_platform_data(struct hdmitx_common *tx_comm, enum HDMITX_PLATFORM_API_TYPE type, void *plt_data); -/*Notify hpd event to all outer modules: vpp by vout, drm, userspace - *bool force_uevent: force send uevent even the hpd state NOT change. +/* + * Notify hpd event to all outer modules: vpp by vout, drm, userspace + * bool force_uevent: force send uevent even the hpd state NOT change */ +int hdmitx_common_notify_ced_status(struct hdmitx_common *tx_comm); +int hdmitx_bootup_notify_hpd_status(struct hdmitx_common *tx_comm, bool force_uevent); int hdmitx_common_notify_hpd_status(struct hdmitx_common *tx_comm, bool force_uevent); -/*packet api*/ +/* packet api */ /* mode = 0 , disable allm; mode 1: set allm; mode -1: */ int hdmitx_common_set_allm_mode(struct hdmitx_common *tx_comm, int mode); -/* avmute function with lock: +/* + * avmute function with lock: * do set mute when mute cmd from any path; * do clear when all path have cleared avmute; */ @@ -370,6 +373,8 @@ __weak bool is_hdr10plus_enable(void) } #endif +/* work for bootup when hpd is high */ +void hdmitx_bootup_plugin_work(struct hdmitx_common *tx_comm); /* common work for plugin/resume, which is done in lock */ void hdmitx_plugin_common_work(struct hdmitx_common *tx_comm); /* common work for plugout */ diff --git a/include/linux/amlogic/media/vout/hdmitx_common/hdmitx_edid.h b/include/linux/amlogic/media/vout/hdmitx_common/hdmitx_edid.h index 610c989cb..c9adc8e87 100644 --- a/include/linux/amlogic/media/vout/hdmitx_common/hdmitx_edid.h +++ b/include/linux/amlogic/media/vout/hdmitx_common/hdmitx_edid.h @@ -114,7 +114,6 @@ struct rx_cap { /*vendor*/ u32 ieeeoui; u8 Max_TMDS_Clock1; /* HDMI1.4b TMDS_CLK */ - u16 physical_addr; /* CEC physical address */ u32 hf_ieeeoui; /* For HDMI Forum */ u32 Max_TMDS_Clock2; /* HDMI2.0 TMDS_CLK */ /* CEA861-F, Table 56, Colorimetry Data Block */ @@ -289,5 +288,7 @@ void hdmitx_edid_print(u8 *edid_buf); void hdmitx_edid_buffer_clear(u8 *edid_buf, int size); void hdmitx_edid_rxcap_clear(struct rx_cap *prxcap); bool is_support_y422(struct rx_cap *prxcap); - +void hdmitx_cec_phy_addr_parse(struct vsdb_phyaddr *vsdb_phy_addr, const u8 *edid_buf); +unsigned char hdmitx_edid_get_cta_block_count(const u8 *edid_buf); +int hdmitx_edid_audio_block_parse(struct rx_cap *prxcap, u8 *block_buf); #endif diff --git a/include/linux/amlogic/media/vout/hdmitx_common/hdmitx_edid_header.h b/include/linux/amlogic/media/vout/hdmitx_common/hdmitx_edid_header.h index b0ca42fdf..6b636716c 100644 --- a/include/linux/amlogic/media/vout/hdmitx_common/hdmitx_edid_header.h +++ b/include/linux/amlogic/media/vout/hdmitx_common/hdmitx_edid_header.h @@ -12,5 +12,6 @@ #include #include #include +#include #endif