hdmitx: remove edid parser in plugin handler [1/1]

PD#SWPL-158055

Problem:
remove edid parser in plugin handler

Solution:
remove edid parser to drm

Verify:
SC2
S5

Test:
DRM-TX-78, DRM-TX-79, DRM-TX-80, DRM-TX-81

Change-Id: I44006093c6fff74c23c98a1e89e5d8666a3ecfc4
Signed-off-by: ruofei.zhao <ruofei.zhao@amlogic.com>
This commit is contained in:
ruofei.zhao
2024-05-13 16:14:18 +08:00
committed by gerrit autosubmit
parent 5bfbb36336
commit 1cafaab93a
9 changed files with 413 additions and 193 deletions
+19 -1
View File
@@ -24,6 +24,7 @@
#include <linux/amlogic/media/vout/hdmitx_common/hdmitx_types.h>
#include <linux/amlogic/media/amvecm/amvecm.h>
#include <linux/miscdevice.h>
#include <linux/amlogic/media/vout/hdmitx_common/hdmitx_edid.h>
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
@@ -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);
/* step3SW: 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);
+63 -24
View File
@@ -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;
}
+81 -46
View File
@@ -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 */
@@ -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
@@ -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,
@@ -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);
@@ -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 */
@@ -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
@@ -12,5 +12,6 @@
#include <linux/amlogic/media/vout/hdmitx_common/hdmitx_format_para.h>
#include <linux/amlogic/media/vout/hdmitx_common/hdmitx_hw_common.h>
#include <linux/amlogic/media/vout/hdmi_tx_ext.h>
#include <media/cec.h>
#endif