hdmitx: add SCDC/CED function [1/1]
authorZongdong Jiao <zongdong.jiao@amlogic.com>
Fri, 14 Jun 2019 08:27:19 +0000 (16:27 +0800)
committerNick Xie <nick@khadas.com>
Mon, 5 Aug 2019 07:00:02 +0000 (15:00 +0800)
PD#SWPL-6361

Problem:
Lack SCDC/CED function to check Rx TMDS status

Solution:
Add SCDC/CED function
By default, this function is not open.
Enable it in board dts file like below:
  &amhdmitx {
cedst_en = <1>;
  };
Also, you can manually enable it by
  'echo 1 > /sys/class/amhdmitx/amhdmitx0/cedst_policy'
Then listen '/sys/class/extcon/hdmi_cedst/uevent'
and check 'cat /sys/class/amhdmitx/amhdmitx0/cedst_count'

Verify:
G12/U212

Change-Id: Ic9c90936bad643ea95d418d7b019eb37210d7123
Signed-off-by: Zongdong Jiao <zongdong.jiao@amlogic.com>
arch/arm/boot/dts/amlogic/mesong12a.dtsi
drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c
drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_scdc.c
drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c
include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_ddc.h
include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h

index a42fd8f..8407dab 100644 (file)
                 */
                ic_type = <10>;
                dongle_mode = <0>;
+               cedst_en = <0>;
                vend_data: vend_data{ /* Should modified by Customer */
                        vendor_name = "Amlogic"; /* Max Chars: 8 */
                        /* standards.ieee.org/develop/regauth/oui/oui.txt */
index 8ea929c..3f072ca 100644 (file)
@@ -111,6 +111,7 @@ struct extcon_dev *hdmitx_extcon_power;
 struct extcon_dev *hdmitx_extcon_hdr;
 struct extcon_dev *hdmitx_extcon_rxsense;
 struct extcon_dev *hdmitx_extcon_hdcp;
+struct extcon_dev *hdmitx_extcon_cedst;
 
 static inline void hdmitx_notify_hpd(int hpd)
 {
@@ -483,6 +484,8 @@ static int set_disp_mode_auto(void)
                hdev->HWOp.CntlConfig(hdev, CONF_CLR_VSDB_PACKET, 0);
                hdev->HWOp.CntlMisc(hdev, MISC_TMDS_PHY_OP, TMDS_PHY_DISABLE);
                hdev->para = hdmi_get_fmt_name("invalid", hdev->fmt_attr);
+               if (hdev->cedst_policy)
+                       cancel_delayed_work(&hdev->work_cedst);
                return -1;
        }
        strncpy(mode, info->name, sizeof(mode));
@@ -583,6 +586,10 @@ static int set_disp_mode_auto(void)
                }
        }
        hdmitx_set_audio(hdev, &(hdev->cur_audio_param));
+       if (hdev->cedst_policy) {
+               cancel_delayed_work(&hdev->work_cedst);
+               queue_delayed_work(hdev->cedst_wq, &hdev->work_cedst, 0);
+       }
        hdev->output_blank_flag = 1;
        hdev->ready = 1;
        return ret;
@@ -3031,6 +3038,82 @@ static ssize_t show_rxsense_policy(struct device *dev,
        return pos;
 }
 
+/* cedst_policy: 0, no CED feature
+ *            1, auto mode, depends on RX scdc_present
+ *            2, forced CED feature
+ */
+static ssize_t store_cedst_policy(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       int val = 0;
+       struct hdmitx_dev *hdev = &hdmitx_device;
+
+       if (isdigit(buf[0])) {
+               val = buf[0] - '0';
+               pr_info("hdmitx: set cedst_policy as %d\n", val);
+               if ((val == 0) || (val == 1) || (val == 2)) {
+                       hdev->cedst_policy = val;
+                       if (val == 1) { /* Auto mode, depends on Rx */
+                               /* check RX scdc_present */
+                               if (hdev->RXCap.scdc_present)
+                                       hdev->cedst_policy = 1;
+                               else
+                                       hdev->cedst_policy = 0;
+                       }
+                       if (val == 2) /* Force mode */
+                               hdev->cedst_policy = 1;
+               } else
+                       pr_info("only accept as 0, 1(auto), or 2(force)\n");
+       }
+       if (hdev->cedst_policy)
+               queue_delayed_work(hdev->cedst_wq, &hdev->work_cedst, 0);
+       else
+               cancel_delayed_work(&hdev->work_cedst);
+
+
+       return count;
+}
+
+static ssize_t show_cedst_policy(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       int pos = 0;
+
+       pos += snprintf(buf + pos, PAGE_SIZE, "%d\n",
+               hdmitx_device.cedst_policy);
+
+       return pos;
+}
+
+static ssize_t show_cedst_count(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       int pos = 0;
+       struct ced_cnt *ced = &hdmitx_device.ced_cnt;
+       struct scdc_locked_st *ch_st = &hdmitx_device.chlocked_st;
+
+       if (!ch_st->clock_detected)
+               pos += snprintf(buf + pos, PAGE_SIZE, "clock undetected\n");
+       if (!ch_st->ch0_locked)
+               pos += snprintf(buf + pos, PAGE_SIZE, "CH0 unlocked\n");
+       if (!ch_st->ch1_locked)
+               pos += snprintf(buf + pos, PAGE_SIZE, "CH1 unlocked\n");
+       if (!ch_st->ch2_locked)
+               pos += snprintf(buf + pos, PAGE_SIZE, "CH2 unlocked\n");
+       if (ced->ch0_valid && ced->ch0_cnt)
+               pos += snprintf(buf + pos, PAGE_SIZE, "CH0 ErrCnt 0x%x\n",
+                       ced->ch0_cnt);
+       if (ced->ch1_valid && ced->ch1_cnt)
+               pos += snprintf(buf + pos, PAGE_SIZE, "CH1 ErrCnt 0x%x\n",
+                       ced->ch1_cnt);
+       if (ced->ch2_valid && ced->ch2_cnt)
+               pos += snprintf(buf + pos, PAGE_SIZE, "CH2 ErrCnt 0x%x\n",
+                       ced->ch2_cnt);
+       memset(ced, 0, sizeof(*ced));
+
+       return pos;
+}
+
 static ssize_t store_sspll(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t count)
 {
@@ -3593,6 +3676,8 @@ static DEVICE_ATTR(sspll, 0664, show_sspll, store_sspll);
 static DEVICE_ATTR(frac_rate_policy, 0664, show_frac_rate, store_frac_rate);
 static DEVICE_ATTR(rxsense_policy, 0644, show_rxsense_policy,
        store_rxsense_policy);
+static DEVICE_ATTR(cedst_policy, 0664, show_cedst_policy, store_cedst_policy);
+static DEVICE_ATTR(cedst_count, 0444, show_cedst_count, NULL);
 static DEVICE_ATTR(hdcp_clkdis, 0664, show_hdcp_clkdis, store_hdcp_clkdis);
 static DEVICE_ATTR(hdcp_pwr, 0664, show_hdcp_pwr, store_hdcp_pwr);
 static DEVICE_ATTR(hdcp_byp, 0200, NULL, store_hdcp_byp);
@@ -3679,6 +3764,11 @@ static int hdmitx_module_disable(enum vmode_e cur_vmod)
                hdmitx_disable_vclk2_enci(hdev);
        hdev->para = hdmi_get_fmt_name("invalid", hdev->fmt_attr);
        hdmitx_validate_vmode("null");
+       if (hdev->cedst_policy)
+               cancel_delayed_work(&hdev->work_cedst);
+       if (hdev->rxsense_policy)
+               queue_delayed_work(hdmitx_device.rxsense_wq,
+                       &hdmitx_device.work_rxsense, 0);
 
        return 0;
 }
@@ -3928,6 +4018,19 @@ static void hdmitx_rxsense_process(struct work_struct *work)
        queue_delayed_work(hdev->rxsense_wq, &hdev->work_rxsense, HZ);
 }
 
+static void hdmitx_cedst_process(struct work_struct *work)
+{
+       int ced;
+       struct hdmitx_dev *hdev = container_of((struct delayed_work *)work,
+               struct hdmitx_dev, work_cedst);
+
+       ced = hdev->HWOp.CntlMisc(hdev, MISC_TMDS_CEDST, 0);
+       /* firstly send as 0, then real ced, A trigger signal */
+       extcon_set_state_sync(hdmitx_extcon_cedst, EXTCON_DISP_HDMI, 0);
+       extcon_set_state_sync(hdmitx_extcon_cedst, EXTCON_DISP_HDMI, ced);
+       queue_delayed_work(hdev->cedst_wq, &hdev->work_cedst, HZ);
+}
+
 static void hdmitx_hpd_plugin_handler(struct work_struct *work)
 {
        char bksv_buf[5];
@@ -3951,6 +4054,7 @@ static void hdmitx_hpd_plugin_handler(struct work_struct *work)
        if (hdev->repeater_tx)
                rx_repeat_hpd_state(1);
        hdmitx_get_edid(hdev);
+       hdev->cedst_policy = hdev->cedst_en & hdev->RXCap.scdc_present;
        hdmi_physcial_size_update(hdev);
        if (hdev->RXCap.ieeeoui != HDMI_IEEEOUI)
                hdev->HWOp.CntlConfig(hdev,
@@ -3981,6 +4085,10 @@ static void hdmitx_hpd_plugin_handler(struct work_struct *work)
        extcon_set_state_sync(hdmitx_extcon_hdmi, EXTCON_DISP_HDMI, 1);
        extcon_set_state_sync(hdmitx_extcon_audio, EXTCON_DISP_HDMI, 1);
        mutex_unlock(&setclk_mutex);
+       /* Should be started at end of output */
+       cancel_delayed_work(&hdev->work_cedst);
+       if (hdev->cedst_policy)
+               queue_delayed_work(hdev->cedst_wq, &hdev->work_cedst, 0);
 }
 
 static void clear_rx_vinfo(struct hdmitx_dev *hdev)
@@ -4005,6 +4113,8 @@ static void hdmitx_hpd_plugout_handler(struct work_struct *work)
        hdev->HWOp.CntlDDC(hdev, DDC_HDCP_MUX_INIT, 1);
        hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP, HDCP14_OFF);
        mutex_lock(&setclk_mutex);
+       if (hdev->cedst_policy)
+               cancel_delayed_work(&hdev->work_cedst);
        pr_info(SYS "plugout\n");
        if (!!(hdev->HWOp.CntlMisc(hdev, MISC_HPD_GPI_ST, 0))) {
                pr_info(SYS "hpd gpio high\n");
@@ -4099,6 +4209,10 @@ static int hdmi_task_handle(void *data)
        hdmitx_device->rxsense_wq = alloc_workqueue(hdmitx_extcon_rxsense->name,
                WQ_SYSFS | WQ_FREEZABLE, 0);
        INIT_DELAYED_WORK(&hdmitx_device->work_rxsense, hdmitx_rxsense_process);
+       /* for cedst feature */
+       hdmitx_device->cedst_wq = alloc_workqueue(hdmitx_extcon_cedst->name,
+               WQ_SYSFS | WQ_FREEZABLE, 0);
+       INIT_DELAYED_WORK(&hdmitx_device->work_cedst, hdmitx_cedst_process);
 
        hdmitx_device->tx_aud_cfg = 1; /* default audio configure is on */
 
@@ -4277,6 +4391,7 @@ void hdmitx_extcon_register(struct platform_device *pdev, struct device *dev)
        ret = extcon_dev_register(edev);
        if (ret < 0) {
                pr_info(SYS "failed to register hdmitx extcon hdmi\n");
+               extcon_dev_free(edev);
                return;
        }
        hdmitx_extcon_hdmi = edev;
@@ -4287,13 +4402,13 @@ void hdmitx_extcon_register(struct platform_device *pdev, struct device *dev)
                pr_info(SYS "failed to allocate hdmitx extcon audio\n");
                return;
        }
-
        edev->dev.parent = dev;
        edev->name = "hdmitx_extcon_audio";
        dev_set_name(&edev->dev, "hdmi_audio");
        ret = extcon_dev_register(edev);
        if (ret < 0) {
                pr_info(SYS "failed to register hdmitx extcon audio\n");
+               extcon_dev_free(edev);
                return;
        }
        hdmitx_extcon_audio = edev;
@@ -4304,13 +4419,13 @@ void hdmitx_extcon_register(struct platform_device *pdev, struct device *dev)
                pr_info(SYS "failed to allocate hdmitx extcon power\n");
                return;
        }
-
        edev->dev.parent = dev;
        edev->name = "hdmitx_extcon_power";
        dev_set_name(&edev->dev, "hdmi_power");
        ret = extcon_dev_register(edev);
        if (ret < 0) {
                pr_info(SYS "failed to register extcon power\n");
+               extcon_dev_free(edev);
                return;
        }
        hdmitx_extcon_power = edev;
@@ -4321,30 +4436,47 @@ void hdmitx_extcon_register(struct platform_device *pdev, struct device *dev)
                pr_info(SYS "failed to allocate hdmitx extcon hdr\n");
                return;
        }
-
        edev->dev.parent = dev;
        edev->name = "hdmitx_extcon_hdr";
        dev_set_name(&edev->dev, "hdmi_hdr");
        ret = extcon_dev_register(edev);
        if (ret < 0) {
                pr_info(SYS "failed to register hdmitx extcon hdr\n");
+               extcon_dev_free(edev);
                return;
        }
        hdmitx_extcon_hdr = edev;
 
-       /*hdmitx extcon rxsense*/
+       /*hdmitx extcon CED */
        edev = extcon_dev_allocate(hdmi_cable);
        if (IS_ERR(edev)) {
                pr_info(SYS "failed to allocate extcon rxsense\n");
                return;
        }
+       edev->dev.parent = dev;
+       edev->name = "hdmitx_extcon_cedst";
+       dev_set_name(&edev->dev, "hdmi_cedst");
+       ret = extcon_dev_register(edev);
+       if (ret < 0) {
+               pr_info(SYS "failed to register extcon cedst\n");
+               extcon_dev_free(edev);
+               return;
+       }
+       hdmitx_extcon_cedst = edev;
 
+       /*hdmitx extcon rxsense*/
+       edev = extcon_dev_allocate(hdmi_cable);
+       if (IS_ERR(edev)) {
+               pr_info(SYS "failed to allocate extcon rxsense\n");
+               return;
+       }
        edev->dev.parent = dev;
        edev->name = "hdmitx_extcon_rxsense";
        dev_set_name(&edev->dev, "hdmi_rxsense");
        ret = extcon_dev_register(edev);
        if (ret < 0) {
                pr_info(SYS "failed to register extcon rxsense\n");
+               extcon_dev_free(edev);
                return;
        }
        hdmitx_extcon_rxsense = edev;
@@ -4355,17 +4487,16 @@ void hdmitx_extcon_register(struct platform_device *pdev, struct device *dev)
                pr_info(SYS "failed to allocate extcon hdcp\n");
                return;
        }
-
        edev->dev.parent = dev;
        edev->name = "hdmitx_extcon_hdcp";
        dev_set_name(&edev->dev, "hdcp");
        ret = extcon_dev_register(edev);
        if (ret < 0) {
                pr_info(SYS "failed to register extcon hdcp\n");
+               extcon_dev_free(edev);
                return;
        }
        hdmitx_extcon_hdcp = edev;
-
 }
 
 static void hdmitx_init_parameters(struct hdmitx_info *info)
@@ -4494,6 +4625,11 @@ static int amhdmitx_get_dt_info(struct platform_device *pdev)
                        hdmitx_device.topo_info = kzalloc(
                                sizeof(*hdmitx_device.topo_info), GFP_KERNEL);
 
+               ret = of_property_read_u32(pdev->dev.of_node,
+                                          "cedst_en", &val);
+               if (!ret)
+                       hdmitx_device.cedst_en = !!val;
+
                /* Get vendor information */
                ret = of_property_read_u32(pdev->dev.of_node,
                                "vend-data", &val);
@@ -4693,6 +4829,8 @@ static int amhdmitx_probe(struct platform_device *pdev)
        ret = device_create_file(dev, &dev_attr_frac_rate_policy);
        ret = device_create_file(dev, &dev_attr_sspll);
        ret = device_create_file(dev, &dev_attr_rxsense_policy);
+       ret = device_create_file(dev, &dev_attr_cedst_policy);
+       ret = device_create_file(dev, &dev_attr_cedst_count);
        ret = device_create_file(dev, &dev_attr_hdcp_clkdis);
        ret = device_create_file(dev, &dev_attr_hdcp_pwr);
        ret = device_create_file(dev, &dev_attr_hdcp_ksv_info);
@@ -4802,6 +4940,8 @@ static int amhdmitx_remove(struct platform_device *pdev)
        device_remove_file(dev, &dev_attr_frac_rate_policy);
        device_remove_file(dev, &dev_attr_sspll);
        device_remove_file(dev, &dev_attr_rxsense_policy);
+       device_remove_file(dev, &dev_attr_cedst_policy);
+       device_remove_file(dev, &dev_attr_cedst_count);
        device_remove_file(dev, &dev_attr_hdcp_pwr);
        device_remove_file(dev, &dev_attr_div40);
        device_remove_file(dev, &dev_attr_hdcp_repeater);
index afb8f5d..54b21c6 100644 (file)
@@ -25,3 +25,74 @@ void scdc_config(struct hdmitx_dev *hdev)
        /* TMDS 1/40 & Scramble */
        scdc_wr_sink(TMDS_CFG, hdev->para->tmds_clk_div40 ? 0x3 : 0);
 }
+
+/* update CED, 10.4.1.8 */
+static int scdc_ced_cnt(struct hdmitx_dev *hdev)
+{
+       struct ced_cnt *ced = &hdev->ced_cnt;
+       u8 raw[7];
+       u8 chksum;
+       int i;
+
+       memset(raw, 0, sizeof(raw));
+       memset(ced, 0, sizeof(struct ced_cnt));
+
+       chksum = 0;
+       for (i = 0; i < 7; i++) {
+               scdc_rd_sink(ERR_DET_0_L + i, &raw[i]);
+               chksum += raw[i];
+       }
+
+       ced->ch0_cnt = raw[0] + ((raw[1] & 0x7f) << 8);
+       ced->ch0_valid = (raw[1] >> 7) & 0x1;
+       ced->ch1_cnt = raw[2] + ((raw[3] & 0x7f) << 8);
+       ced->ch1_valid = (raw[3] >> 7) & 0x1;
+       ced->ch2_cnt = raw[4] + ((raw[5] & 0x7f) << 8);
+       ced->ch2_valid = (raw[5] >> 7) & 0x1;
+
+       /* Do checksum */
+       if (chksum != 0)
+               pr_info("ced check sum error\n");
+       if (ced->ch0_cnt)
+               pr_info("ced: ch0_cnt = %d %s\n", ced->ch0_cnt,
+                       ced->ch0_valid ? "" : "unvalid");
+       if (ced->ch1_cnt)
+               pr_info("ced: ch1_cnt = %d %s\n", ced->ch1_cnt,
+                       ced->ch1_valid ? "" : "unvalid");
+       if (ced->ch2_cnt)
+               pr_info("ced: ch2_cnt = %d %s\n", ced->ch2_cnt,
+                       ced->ch2_valid ? "" : "unvalid");
+
+       return chksum != 0;
+}
+
+/* update scdc status flags, 10.4.1.7 */
+/* ignore STATUS_FLAGS_1, all bits are RSVD */
+int scdc_status_flags(struct hdmitx_dev *hdev)
+{
+       u8 st = 0;
+       u8 locked_st = 0;
+
+       scdc_rd_sink(UPDATE_0, &st);
+       if (st & STATUS_UPDATE) {
+               scdc_rd_sink(STATUS_FLAGS_0, &locked_st);
+               hdev->chlocked_st.clock_detected = locked_st & (1 << 0);
+               hdev->chlocked_st.ch0_locked = !!(locked_st & (1 << 1));
+               hdev->chlocked_st.ch1_locked = !!(locked_st & (2 << 1));
+               hdev->chlocked_st.ch2_locked = !!(locked_st & (3 << 1));
+       }
+       if (st & CED_UPDATE)
+               scdc_ced_cnt(hdev);
+       if (st & (STATUS_UPDATE | CED_UPDATE))
+               scdc_wr_sink(UPDATE_0, st & (STATUS_UPDATE | CED_UPDATE));
+       if (!hdev->chlocked_st.clock_detected)
+               pr_info("ced: clock undetected\n");
+       if (!hdev->chlocked_st.ch0_locked)
+               pr_info("ced: ch0 unlocked\n");
+       if (!hdev->chlocked_st.ch1_locked)
+               pr_info("ced: ch1 unlocked\n");
+       if (!hdev->chlocked_st.ch2_locked)
+               pr_info("ced: ch2 unlocked\n");
+
+       return st & (STATUS_UPDATE | CED_UPDATE);
+}
index b48e819..171c1db 100644 (file)
@@ -5001,6 +5001,13 @@ static int hdmitx_tmds_rxsense(void)
        return ret;
 }
 
+/*Check from SCDC Status_Flags_0/1 */
+/* 0 means TMDS ok */
+static int hdmitx_tmds_cedst(struct hdmitx_dev *hdev)
+{
+       return scdc_status_flags(hdev);
+}
+
 static int hdmitx_cntl_misc(struct hdmitx_dev *hdev, unsigned int cmd,
        unsigned int argv)
 {
@@ -5031,6 +5038,8 @@ static int hdmitx_cntl_misc(struct hdmitx_dev *hdev, unsigned int cmd,
                break;
        case MISC_TMDS_RXSENSE:
                return hdmitx_tmds_rxsense();
+       case MISC_TMDS_CEDST:
+               return hdmitx_tmds_cedst(hdev);
        case MISC_ESM_RESET:
                if (hdev->hdcp_hpd_stick == 1) {
                        pr_info(HW "hdcp: stick mode\n");
index 45c2d3f..e0be30d 100644 (file)
@@ -19,7 +19,7 @@
 #define __HDMI_TX_DDC_H__
 
 #include <linux/types.h>
-#include <linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h>
+#include "hdmi_tx_module.h"
 
 #define EDID_SLAVE     0x50
        #define EDIDSEG_ADR     0x30
@@ -31,6 +31,9 @@ enum scdc_addr {
        SINK_VER = 0x01,
        SOURCE_VER, /* RW */
        UPDATE_0 = 0x10, /* RW */
+#define STATUS_UPDATE  BIT(0)
+#define CED_UPDATE     BIT(1)
+#define RR_TEST                BIT(2)
        UPDATE_1, /* RW */
        TMDS_CFG = 0x20, /* RW */
        SCRAMBLER_ST,
@@ -83,5 +86,6 @@ uint32_t hdcp_rd_hdcp14_ver(void);
 uint32_t hdcp_rd_hdcp22_ver(void);
 void scdc_config(struct hdmitx_dev *hdev);
 void edid_read_head_8bytes(void);
+int scdc_status_flags(struct hdmitx_dev *hdev);
 
 #endif  /* __HDMI_TX_SCDC_H__ */
index 5b85d43..697407d 100644 (file)
@@ -202,6 +202,23 @@ struct frac_rate_table {
        u32 sync_den_dec;
 };
 
+struct ced_cnt {
+       bool ch0_valid;
+       u16 ch0_cnt:15;
+       bool ch1_valid;
+       u16 ch1_cnt:15;
+       bool ch2_valid;
+       u16 ch2_cnt:15;
+       u8 chksum;
+};
+
+struct scdc_locked_st {
+       u8 clock_detected:1;
+       u8 ch0_locked:1;
+       u8 ch1_locked:1;
+       u8 ch2_locked:1;
+};
+
 enum hdmi_hdr_transfer {
        T_UNKNOWN = 0,
        T_BT709,
@@ -302,6 +319,7 @@ struct hdmitx_dev {
        struct notifier_block nb;
        struct workqueue_struct *hdmi_wq;
        struct workqueue_struct *rxsense_wq;
+       struct workqueue_struct *cedst_wq;
        struct device *hdtx_dev;
        struct device *pdev; /* for pinctrl*/
        struct pinctrl_state *pinctrl_i2c;
@@ -310,6 +328,7 @@ struct hdmitx_dev {
        struct delayed_work work_hpd_plugout;
        struct delayed_work work_rxsense;
        struct delayed_work work_internal_intr;
+       struct delayed_work work_cedst;
        struct work_struct work_hdr;
        struct delayed_work work_do_hdcp;
 #ifdef CONFIG_AML_HDMI_TX_14
@@ -422,6 +441,9 @@ struct hdmitx_dev {
        /* 0.1% clock shift, 1080p60hz->59.94hz */
        unsigned int frac_rate_policy;
        unsigned int rxsense_policy;
+       unsigned int cedst_policy;
+       struct ced_cnt ced_cnt;
+       struct scdc_locked_st chlocked_st;
        /* allm_mode: 1/game, 2/graphcis, 3/photo, 4/cinema */
        unsigned int allm_mode;
        unsigned int sspll;
@@ -449,6 +471,7 @@ struct hdmitx_dev {
        unsigned int flag_3dtb:1;
        unsigned int flag_3dss:1;
        unsigned int dongle_mode:1;
+       unsigned int cedst_en:1; /* configure in DTS */
        unsigned int drm_feature;/*Direct Rander Management*/
 };
 
@@ -564,9 +587,10 @@ struct hdmitx_dev {
 #define MISC_ESM_RESET         (CMD_MISC_OFFSET + 0x0d)
 #define MISC_HDCP_CLKDIS       (CMD_MISC_OFFSET + 0x0e)
 #define MISC_TMDS_RXSENSE      (CMD_MISC_OFFSET + 0x0f)
-#define MISC_I2C_REACTIVE       (CMD_MISC_OFFSET + 0x10)
-#define MISC_I2C_RESET         (CMD_MISC_OFFSET + 0x11)
+#define MISC_I2C_REACTIVE       (CMD_MISC_OFFSET + 0x10) /* For gxl */
+#define MISC_I2C_RESET         (CMD_MISC_OFFSET + 0x11) /* For g12 */
 #define MISC_READ_AVMUTE_OP     (CMD_MISC_OFFSET + 0x12)
+#define MISC_TMDS_CEDST                (CMD_MISC_OFFSET + 0x13)
 
 /***********************************************************************
  *                          Get State //GetState