hdmitx: add init code for repeater [2/6]
authorZongdong Jiao <zongdong.jiao@amlogic.com>
Sat, 29 Sep 2018 10:20:21 +0000 (18:20 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Tue, 30 Oct 2018 11:35:08 +0000 (04:35 -0700)
PD#SWPL-323

Problem:
For TXLX/T962E, it has both HDMI Rx and TX, and lacks of HDMI repeater
functions, including HDCP repeater function.

Solution:
Add the init code for hdmi repeater

Verify:
TXLX/T962E/R321

Change-Id: Iaf17ae62c590ff4f8478dd5556f3ed24b9ff3bb1
Signed-off-by: Zongdong Jiao <zongdong.jiao@amlogic.com>
MAINTAINERS
drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_edid.c
drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_hdcp.h
drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c
drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c
include/linux/amlogic/media/vout/hdmi_tx/hdmi_info_global.h
include/linux/amlogic/media/vout/hdmi_tx/hdmi_rptx.h [new file with mode: 0644]
include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h

index 608febc..819c4e1 100644 (file)
@@ -13539,8 +13539,8 @@ F: arch/arm/mach-meson/Makefile.boot
 
 HDMITX OUTPUT DRIVER
 M:     Yi Zhou <yi.zhou@amlogic.com>
-M:     Kaifu Hu <kaifu.hu@amlogic.com>
 M:      Zongdong Jiao <zongdong.jiao@amlogic.com>
+M:     Kaifu Hu <kaifu.hu@amlogic.com>
 S:     Maintained
 F:     drivers/amlogic/media/vout/hdmitx/*
 F:     drivers/amlogic/media/vout/hdmitx/hdcp/*
index 41520ce..6a190f7 100644 (file)
@@ -305,14 +305,16 @@ int Edid_Parse_check_HDMI_VSDB(struct hdmitx_dev *hdev,
        }
 
        set_vsdb_phy_addr(hdev, &info->vsdb_phy_addr, &buff[BlockAddr]);
-       if ((check_fbc_special(&hdev->EDID_buf[0])) ||
-           (check_fbc_special(&hdev->EDID_buf1[0])))
-               rx_edid_physical_addr(0, 0, 0, 0);
-       else
-               rx_edid_physical_addr(info->vsdb_phy_addr.a,
-                       info->vsdb_phy_addr.b,
-                       info->vsdb_phy_addr.c,
-                       info->vsdb_phy_addr.d);
+       if (hdev->repeater_tx) {
+               if ((check_fbc_special(&hdev->EDID_buf[0])) ||
+                   (check_fbc_special(&hdev->EDID_buf1[0])))
+                       rx_edid_physical_addr(0, 0, 0, 0);
+               else
+                       rx_edid_physical_addr(info->vsdb_phy_addr.a,
+                               info->vsdb_phy_addr.b,
+                               info->vsdb_phy_addr.c,
+                               info->vsdb_phy_addr.d);
+       }
 
        if (temp_addr >= VSpecificBoundary)
                ret = -1;
@@ -1203,18 +1205,15 @@ static void Edid_Y420CMDB_Reset(struct hdmitx_info *info)
        memset(info->y420cmdb_bitmap, 0x00, Y420CMDB_MAX);
 }
 
-static char *rptx_edid_aud;
-static char rptx_edid_buf[512];
-MODULE_PARM_DESC(rptx_edid_aud, "\n receive_edid\n");
-module_param(rptx_edid_aud, charp, 0444);
-
 /* ----------------------------------------------------------- */
 int Edid_ParsingCEADataBlockCollection(struct hdmitx_dev *hdmitx_device,
        unsigned char *buff)
 {
        unsigned char AddrTag, D, Addr, Data;
-       int temp_addr, i, len, pos;
+       int temp_addr;
+       int len;
        struct hdmitx_info *info = &(hdmitx_device->hdmi_info);
+       struct rx_cap *pRXCap = &hdmitx_device->RXCap;
 
        /* Byte number offset d where Detailed Timing data begins */
        D = buff[2];
@@ -1225,22 +1224,29 @@ int Edid_ParsingCEADataBlockCollection(struct hdmitx_dev *hdmitx_device,
                Data = buff[AddrTag];
                switch (Data&0xE0) {
                case VIDEO_TAG:
-                       if ((Addr + (Data&0x1f)) < D)
+                       if ((Addr + (Data&0x1f)) < D) {
                                Edid_ParsingVideoDATABlock(info, buff,
                                        Addr + 1, (Data & 0x1F));
+                               len = (Data & 0x1f) + 1;
+                               if ((pRXCap->vsd.len + len) > MAX_RAW_LEN)
+                                       break;
+                               memcpy(&pRXCap->vsd.raw[pRXCap->vsd.len],
+                                       &buff[AddrTag], len);
+                               pRXCap->vsd.len += len;
+                       }
                        break;
 
                case AUDIO_TAG:
-                       len = (Data & 0x1f) + 1;
-                       if (hdmitx_device->repeater_tx)
-                               rx_set_receiver_edid(&buff[AddrTag], len);
-                       for (pos = 0, i = 0; i < len; i++)
-                               pos += sprintf(rptx_edid_buf+pos, "%02x",
-                                       buff[AddrTag + i]);
-                       rptx_edid_buf[pos + 1] = 0;
+                       /* rx_set_receiver_edid(&buff[AddrTag], len); */
                        if ((Addr + (Data&0x1f)) < D)
                                Edid_ParsingAudioDATABlock(info, buff,
                                        Addr + 1, (Data & 0x1F));
+                       len = (Data & 0x1f) + 1;
+                       if ((pRXCap->asd.len + len) > MAX_RAW_LEN)
+                               break;
+                       memcpy(&pRXCap->asd.raw[pRXCap->asd.len],
+                               &buff[AddrTag], len);
+                       pRXCap->asd.len += len;
                        break;
 
                case SPEAKER_TAG:
@@ -1965,10 +1971,12 @@ int hdmitx_edid_parse(struct hdmitx_dev *hdmitx_device)
                        EDID_MAX_BLOCK * 128);
        } else
                EDID_buf = hdmitx_device->EDID_buf1;
+
+       if (check_dvi_hdmi_edid_valid(hdmitx_device->EDID_buf1))
+               hdmitx_device->edid_parsing = 1;
+
        hdmitx_device->edid_ptr = EDID_buf;
        pr_info(EDID "EDID Parser:\n");
-       memset(rptx_edid_buf, 0, sizeof(rptx_edid_buf));
-       rptx_edid_aud = &rptx_edid_buf[0];
        /* Calculate the EDID hash for special use */
        memset(hdmitx_device->EDID_hash, 0,
                ARRAY_SIZE(hdmitx_device->EDID_hash));
index ae39f44..88c2b6f 100644 (file)
@@ -27,7 +27,6 @@
  * other devices
  */
 extern int hdcp_ksv_valid(unsigned char *dat);
-extern unsigned int hdcp_get_downstream_ver(void);
 
 #endif
 
index 98bd1d7..d2e05e8 100644 (file)
@@ -125,6 +125,7 @@ static void hdmitx_early_suspend(struct early_suspend *h)
                || strncmp(info->name, "null", 4) == 0))
                return;
 
+       phdmi->ready = 0;
        phdmi->hpd_lock = 1;
        msleep(20);
        phdmi->HWOp.CntlMisc(phdmi, MISC_AVMUTE_OP, SET_AVMUTE);
@@ -184,7 +185,7 @@ static void hdmitx_late_resume(struct early_suspend *h)
 
                /* update status for hpd and switch/state */
                hdmitx_device.hpd_state =
-               !!(hdmitx_device.HWOp.CntlMisc(&hdmitx_device,
+                       !!(hdmitx_device.HWOp.CntlMisc(&hdmitx_device,
                MISC_HPD_GPI_ST, 0));
 
                pr_info("hdmitx hpd state: %d\n", hdmitx_device.hpd_state);
@@ -218,6 +219,7 @@ static int hdmitx_reboot_notifier(struct notifier_block *nb,
 {
        struct hdmitx_dev *hdev = container_of(nb, struct hdmitx_dev, nb);
 
+       hdev->ready = 0;
        hdev->HWOp.CntlMisc(hdev, MISC_AVMUTE_OP, SET_AVMUTE);
        mdelay(100);
        hdev->HWOp.CntlMisc(hdev, MISC_TMDS_PHY_OP, TMDS_PHY_DISABLE);
@@ -447,6 +449,7 @@ static int set_disp_mode_auto(void)
                hdev, STAT_VIDEO_VIC, 0);
 
        memset(mode, 0, sizeof(mode));
+       hdev->ready = 0;
 
        /* get current vinfo */
        info = hdmitx_get_current_vinfo();
@@ -621,6 +624,83 @@ void setup_attr(const char *buf)
 }
 EXPORT_SYMBOL(setup_attr);
 
+
+/* for android application data exchange / swap */
+static char *tmp_swap;
+static DEFINE_MUTEX(mutex_swap);
+
+static ssize_t store_swap(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       pr_info("store_swap: %s\n", buf);
+       mutex_lock(&mutex_swap);
+
+       kfree(tmp_swap);
+       tmp_swap = kzalloc(count + 1, GFP_KERNEL);
+       if (!tmp_swap) {
+               mutex_unlock(&mutex_swap);
+               return count;
+       }
+       memcpy(tmp_swap, buf, count);
+       tmp_swap[count] = '\0'; /* padding end string */
+       mutex_unlock(&mutex_swap);
+       return count;
+}
+
+static ssize_t show_swap(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       int i = 0;
+       int n = 0;
+       struct hdmitx_dev *hdev = &hdmitx_device;
+       struct rx_cap *pRXCap = &hdev->RXCap;
+       struct hdcprp14_topo *topo14 = &hdev->topo_info->topo.topo14;
+
+       mutex_lock(&mutex_swap);
+
+       if (!tmp_swap ||
+               (!hdev->edid_parsing && !strstr(tmp_swap, "hdcp.topo"))) {
+               mutex_unlock(&mutex_swap);
+               return n;
+       }
+
+       /* VSD: Video Short Descriptor */
+       if (strstr(tmp_swap, "edid.vsd"))
+               for (i = 0; i < pRXCap->vsd.len; i++)
+                       n += snprintf(buf + n, PAGE_SIZE - n, "%02x",
+                               pRXCap->vsd.raw[i]);
+       /* ASD: Audio Short Descriptor */
+       if (strstr(tmp_swap, "edid.asd"))
+               for (i = 0; i < pRXCap->asd.len; i++)
+                       n += snprintf(buf + n, PAGE_SIZE - n, "%02x",
+                               pRXCap->asd.raw[i]);
+       /* CEC: Physical Address */
+       if (strstr(tmp_swap, "edid.cec"))
+               n += snprintf(buf + n, PAGE_SIZE - n, "%x%x%x%x",
+                       hdev->hdmi_info.vsdb_phy_addr.a,
+                       hdev->hdmi_info.vsdb_phy_addr.b,
+                       hdev->hdmi_info.vsdb_phy_addr.c,
+                       hdev->hdmi_info.vsdb_phy_addr.d);
+       /* HDCP TOPO */
+       if (strstr(tmp_swap, "hdcp.topo")) {
+               char *tmp = (char *)topo14;
+
+               pr_info("max_cascade_exceeded %d\n",
+                       topo14->max_cascade_exceeded);
+               pr_info("depth %d\n", topo14->depth);
+               pr_info("max_devs_exceeded %d\n", topo14->max_devs_exceeded);
+               pr_info("device_count %d\n", topo14->device_count);
+               for (i = 0; i < sizeof(struct hdcprp14_topo); i++)
+                       n += snprintf(buf + n, PAGE_SIZE - n, "%02x", tmp[i]);
+       }
+
+       kfree(tmp_swap);
+       tmp_swap = NULL;
+
+       mutex_unlock(&mutex_swap);
+       return n;
+}
+
 static ssize_t show_aud_mode(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
@@ -2584,24 +2664,53 @@ static ssize_t store_avmute(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t count)
 {
        int cmd = OFF_AVMUTE;
+       static int mask0;
+       static int mask1;
+       static DEFINE_MUTEX(avmute_mutex);
 
-       if (strncmp(buf, "-1", 2) == 0)
+       pr_info("store_avmute %s\n", buf);
+       mutex_lock(&avmute_mutex);
+       if (strncmp(buf, "-1", 2) == 0) {
                cmd = CLR_AVMUTE;
-       else if (strncmp(buf, "0", 1) == 0)
+               mask0 = -1;
+       } else if (strncmp(buf, "0", 1) == 0) {
                cmd = OFF_AVMUTE;
-       else if (strncmp(buf, "1", 1) == 0)
+               mask0 = 0;
+       } else if (strncmp(buf, "1", 1) == 0) {
                cmd = SET_AVMUTE;
-       else
-               pr_info(SYS "set avmute wrong: %s\n", buf);
-
+               mask0 = 1;
+       }
+       if (strncmp(buf, "r-1", 3) == 0) {
+               cmd = CLR_AVMUTE;
+               mask1 = -1;
+       } else if (strncmp(buf, "r0", 2) == 0) {
+               cmd = OFF_AVMUTE;
+               mask1 = 0;
+       } else if (strncmp(buf, "r1", 2) == 0) {
+               cmd = SET_AVMUTE;
+               mask1 = 1;
+       }
+       if ((mask0 == 1) || (mask1 == 1))
+               cmd = SET_AVMUTE;
+       else if ((mask0 == -1) && (mask1 == -1))
+               cmd = CLR_AVMUTE;
        hdmitx_device.HWOp.CntlMisc(&hdmitx_device, MISC_AVMUTE_OP, cmd);
+       mutex_unlock(&avmute_mutex);
+
        return count;
 }
 
 static ssize_t show_avmute(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
-       return 0;
+       struct hdmitx_dev *hdev = &hdmitx_device;
+       int ret = 0;
+       int pos = 0;
+
+       ret = hdev->HWOp.CntlMisc(hdev, MISC_READ_AVMUTE_OP, 0);
+       pos += snprintf(buf + pos, PAGE_SIZE, "%d", ret);
+
+       return pos;
 }
 
 /*
@@ -2807,6 +2916,13 @@ static ssize_t show_hdcp_lstore(struct device *dev,
 {
        int pos = 0;
 
+       /* if current TX is RP-TX, then return lstore as 00 */
+       /* hdcp_lstore is used under only TX */
+       if (hdmitx_device.repeater_tx == 1) {
+               pos += snprintf(buf + pos, PAGE_SIZE, "00\n");
+               return pos;
+       }
+
        if (hdmitx_device.lstore < 0x10) {
                hdmitx_device.lstore = 0;
                if (hdmitx_device.HWOp.CntlDDC(&hdmitx_device,
@@ -2841,6 +2957,53 @@ static ssize_t store_hdcp_lstore(struct device *dev,
        return count;
 }
 
+static int rptxlstore;
+static ssize_t show_hdcp_rptxlstore(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       int pos = 0;
+
+       /* if current TX is not RP-TX, then return rptxlstore as 00 */
+       /* hdcp_rptxlstore is used under only RP-TX */
+       if (hdmitx_device.repeater_tx == 0) {
+               pos += snprintf(buf + pos, PAGE_SIZE, "00\n");
+               return pos;
+       }
+
+       if (rptxlstore < 0x10) {
+               rptxlstore = 0;
+               if (hdmitx_device.HWOp.CntlDDC(&hdmitx_device,
+                       DDC_HDCP_14_LSTORE, 0))
+                       rptxlstore += 1;
+               if (hdmitx_device.HWOp.CntlDDC(&hdmitx_device,
+                       DDC_HDCP_22_LSTORE, 0))
+                       rptxlstore += 2;
+       }
+       if (rptxlstore & 0x1)
+               pos += snprintf(buf + pos, PAGE_SIZE, "14\n");
+       if (rptxlstore & 0x2)
+               pos += snprintf(buf + pos, PAGE_SIZE, "22\n");
+       if ((rptxlstore & 0xf) == 0)
+               pos += snprintf(buf + pos, PAGE_SIZE, "00\n");
+       return pos;
+}
+
+static ssize_t store_hdcp_rptxlstore(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       pr_info("hdcp: set lstore as %s\n", buf);
+       if (strncmp(buf, "0", 1) == 0)
+               rptxlstore = 0x10;
+       if (strncmp(buf, "11", 2) == 0)
+               rptxlstore = 0x11;
+       if (strncmp(buf, "12", 2) == 0)
+               rptxlstore = 0x12;
+       if (strncmp(buf, "13", 2) == 0)
+               rptxlstore = 0x13;
+
+       return count;
+}
+
 static ssize_t show_div40(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
@@ -2919,39 +3082,119 @@ static ssize_t store_hdcp_mode(struct device *dev,
        return count;
 }
 
-void direct_hdcptx14_start(void)
+static bool hdcp_sticky_mode;
+static ssize_t show_hdcp_stickmode(struct device *dev,
+       struct device_attribute *attr, char *buf)
 {
-       pr_info("%s[%d]", __func__, __LINE__);
-       hdmitx_device.hdcp_mode = 1;
-       hdmitx_device.HWOp.CntlDDC(&hdmitx_device,
-                       DDC_HDCP_OP, HDCP14_ON);
+       int pos = 0;
+
+       pos += snprintf(buf+pos, PAGE_SIZE, "%d\n", hdcp_sticky_mode);
+
+       return pos;
 }
-EXPORT_SYMBOL(direct_hdcptx14_start);
 
-void direct_hdcptx14_stop(void)
+static ssize_t store_hdcp_stickmode(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
 {
-       pr_info("%s[%d]", __func__, __LINE__);
-       hdmitx_device.HWOp.CntlDDC(&hdmitx_device,
-               DDC_HDCP_OP, HDCP14_OFF);
+       if (buf[0] == '0')
+               hdcp_sticky_mode = 0;
+       if (buf[0] == '1')
+               hdcp_sticky_mode = 1;
+
+       return count;
+}
+
+static unsigned char hdcp_sticky_step;
+static ssize_t show_hdcp_stickstep(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       int pos = 0;
+
+       pos += snprintf(buf+pos, PAGE_SIZE, "%x\n", hdcp_sticky_step);
+       if (hdcp_sticky_step)
+               hdcp_sticky_step = 0;
+
+       return pos;
+}
+
+static ssize_t store_hdcp_stickstep(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       if (isdigit(buf[0]))
+               hdcp_sticky_step = buf[0] - '0';
+
+       return count;
+}
+
+/* Indicate whether a rptx under repeater */
+static ssize_t show_repeater_tx(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       int pos = 0;
+
+       pos += snprintf(buf+pos, PAGE_SIZE, "%d\n",
+               !!hdmitx_device.repeater_tx);
+
+       return pos;
+}
+
+#include <linux/amlogic/media/vout/hdmi_tx/hdmi_rptx.h>
+
+void direct_hdcptx14_opr(enum rptx_hdcp14_cmd cmd, void *args)
+{
+       int rst;
+       struct hdmitx_dev *hdev = &hdmitx_device;
+
+       pr_info("%s[%d] cmd: %d\n", __func__, __LINE__, cmd);
+       switch (cmd) {
+       case RPTX_HDCP14_OFF:
+               hdev->hdcp_mode = 0;
+               hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP, HDCP14_OFF);
+               break;
+       case RPTX_HDCP14_ON:
+               hdev->hdcp_mode = 1;
+               hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP, HDCP14_ON);
+               break;
+       case RPTX_HDCP14_GET_AUTHST:
+               rst = hdev->HWOp.CntlDDC(hdev, DDC_HDCP_GET_AUTH, 0);
+               *(int *)args = rst;
+               break;
+       }
 }
-EXPORT_SYMBOL(direct_hdcptx14_stop);
+EXPORT_SYMBOL(direct_hdcptx14_opr);
 
 static ssize_t store_hdcp_ctrl(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t count)
 {
-       if (hdmitx_device.HWOp.CntlDDC(&hdmitx_device, DDC_HDCP_14_LSTORE,
-               0) == 0)
+       struct hdmitx_dev *hdev = &hdmitx_device;
+
+       if (hdev->HWOp.CntlDDC(hdev, DDC_HDCP_14_LSTORE, 0) == 0)
+               return count;
+
+       /* for repeater */
+       if (hdev->repeater_tx) {
+               dev_warn(dev, "hdmitx20: %s\n", buf);
+               if (strncmp(buf, "rstop", 5) == 0) {
+                       if (strncmp(buf+5, "14", 2) == 0)
+                               hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP,
+                                       HDCP14_OFF);
+                       if (strncmp(buf+5, "22", 2) == 0)
+                               hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP,
+                                       HDCP22_OFF);
+                       hdev->hdcp_mode = 0;
+                       hdmitx_hdcp_do_work(hdev);
+               }
                return count;
-       dev_warn(dev, "hdmitx20: %s\n", buf);
+       }
+       /* for non repeater */
        if (strncmp(buf, "stop", 4) == 0) {
+               dev_warn(dev, "hdmitx20: %s\n", buf);
                if (strncmp(buf+4, "14", 2) == 0)
-                       hdmitx_device.HWOp.CntlDDC(&hdmitx_device,
-                               DDC_HDCP_OP, HDCP14_OFF);
+                       hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP, HDCP14_OFF);
                if (strncmp(buf+4, "22", 2) == 0)
-                       hdmitx_device.HWOp.CntlDDC(&hdmitx_device,
-                               DDC_HDCP_OP, HDCP22_OFF);
-               hdmitx_device.hdcp_mode = 0;
-               hdmitx_hdcp_do_work(&hdmitx_device);
+                       hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP, HDCP22_OFF);
+               hdev->hdcp_mode = 0;
+               hdmitx_hdcp_do_work(hdev);
        }
 
        return count;
@@ -3035,6 +3278,26 @@ static ssize_t show_hpd_state(struct device *dev,
        return pos;
 }
 
+
+static ssize_t show_rhpd_state(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       struct hdmitx_dev *hdev = &hdmitx_device;
+       int st;
+
+       st = hdev->HWOp.CntlMisc(hdev, MISC_HPD_GPI_ST, 0);
+
+       return snprintf(buf, PAGE_SIZE, "%d", hdev->rhpd_state);
+}
+
+static ssize_t show_max_exceed_state(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       struct hdmitx_dev *hdev = &hdmitx_device;
+
+       return snprintf(buf, PAGE_SIZE, "%d", hdev->hdcp_max_exceed_state);
+}
+
 static ssize_t show_hdmi_init(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
@@ -3093,6 +3356,7 @@ static DEVICE_ATTR(dc_cap, 0444, show_dc_cap, NULL);
 static DEVICE_ATTR(valid_mode, 0664, show_valid_mode, store_valid_mode);
 static DEVICE_ATTR(aud_ch, 0664, show_aud_ch, store_aud_ch);
 static DEVICE_ATTR(avmute, 0664, show_avmute, store_avmute);
+static DEVICE_ATTR(swap, 0644, show_swap, store_swap);
 static DEVICE_ATTR(vic, 0664, show_vic, store_vic);
 static DEVICE_ATTR(phy, 0664, show_phy, store_phy);
 static DEVICE_ATTR(sspll, 0664, show_sspll, store_sspll);
@@ -3104,11 +3368,18 @@ static DEVICE_ATTR(hdcp_pwr, 0664, show_hdcp_pwr, store_hdcp_pwr);
 static DEVICE_ATTR(hdcp_byp, 0200, NULL, store_hdcp_byp);
 static DEVICE_ATTR(hdcp_mode, 0664, show_hdcp_mode, store_hdcp_mode);
 static DEVICE_ATTR(hdcp_lstore, 0664, show_hdcp_lstore, store_hdcp_lstore);
+static DEVICE_ATTR(hdcp_rptxlstore, 0664, show_hdcp_rptxlstore,
+       store_hdcp_rptxlstore);
 static DEVICE_ATTR(hdcp_repeater, 0644, show_hdcp_repeater,
        store_hdcp_repeater);
 static DEVICE_ATTR(hdcp_topo_info, 0644, show_hdcp_topo_info,
        store_hdcp_topo_info);
 static DEVICE_ATTR(hdcp22_type, 0644, show_hdcp22_type, store_hdcp22_type);
+static DEVICE_ATTR(hdcp_stickmode, 0664, show_hdcp_stickmode,
+       store_hdcp_stickmode);
+static DEVICE_ATTR(hdcp_stickstep, 0664, show_hdcp_stickstep,
+       store_hdcp_stickstep);
+static DEVICE_ATTR(hdmi_repeater_tx, 0444, show_repeater_tx, NULL);
 static DEVICE_ATTR(hdcp22_base, 0444, show_hdcp22_base, NULL);
 static DEVICE_ATTR(div40, 0664, show_div40, store_div40);
 static DEVICE_ATTR(hdcp_ctrl, 0664, show_hdcp_ctrl, store_hdcp_ctrl);
@@ -3116,6 +3387,8 @@ static DEVICE_ATTR(disp_cap_3d, 0444, show_disp_cap_3d, NULL);
 static DEVICE_ATTR(hdcp_ksv_info, 0444, show_hdcp_ksv_info, NULL);
 static DEVICE_ATTR(hdcp_ver, 0444, show_hdcp_ver, NULL);
 static DEVICE_ATTR(hpd_state, 0444, show_hpd_state, NULL);
+static DEVICE_ATTR(rhpd_state, 0444, show_rhpd_state, NULL);
+static DEVICE_ATTR(max_exceed, 0444, show_max_exceed_state, NULL);
 static DEVICE_ATTR(hdmi_init, 0444, show_hdmi_init, NULL);
 static DEVICE_ATTR(ready, 0664, show_ready, store_ready);
 static DEVICE_ATTR(support_3d, 0444, show_support_3d, NULL);
@@ -3439,9 +3712,11 @@ static void hdmitx_hpd_plugin_handler(struct work_struct *work)
        }
        mutex_lock(&setclk_mutex);
        pr_info(SYS "plugin\n");
+       hdev->HWOp.CntlMisc(hdev, MISC_I2C_REACTIVE, 0);
        hdev->hdmitx_event &= ~HDMI_TX_HPD_PLUGIN;
        /* start reading E-EDID */
-       rx_repeat_hpd_state(1);
+       if (hdev->repeater_tx)
+               rx_repeat_hpd_state(1);
        hdmitx_get_edid(hdev);
        hdmi_physcial_size_update(hdev);
        if (hdev->RXCap.IEEEOUI != 0x000c03)
@@ -3451,7 +3726,6 @@ static void hdmitx_hpd_plugin_handler(struct work_struct *work)
                hdev->HWOp.CntlConfig(hdev,
                        CONF_HDMI_DVI_MODE, HDMI_MODE);
        mutex_lock(&getedid_mutex);
-       hdev->HWOp.CntlMisc(hdev, MISC_I2C_REACTIVE, 0);
        mutex_unlock(&getedid_mutex);
        if (hdev->repeater_tx) {
                if (check_fbc_special(&hdev->EDID_buf[0])
@@ -3459,7 +3733,6 @@ static void hdmitx_hpd_plugin_handler(struct work_struct *work)
                        rx_set_repeater_support(0);
                else
                        rx_set_repeater_support(1);
-               rx_repeat_hdcp_ver(hdcp_get_downstream_ver());
                hdev->HWOp.CntlDDC(hdev, DDC_HDCP_GET_BKSV,
                        (unsigned long int)bksv_buf);
                rx_set_receive_hdcp(bksv_buf, 1, 1, 0, 0);
@@ -3512,7 +3785,8 @@ static void hdmitx_hpd_plugout_handler(struct work_struct *work)
                return;
        hdev->hdcp_mode = 0;
        hdev->hdcp_bcaps_repeater = 0;
-
+       hdev->HWOp.CntlDDC(hdev, DDC_HDCP_MUX_INIT, 1);
+       hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP, HDCP14_OFF);
        mutex_lock(&setclk_mutex);
        pr_info(SYS "plugout\n");
        if (!!(hdev->HWOp.CntlMisc(hdev, MISC_HPD_GPI_ST, 0))) {
@@ -3984,6 +4258,14 @@ static int amhdmitx_get_dt_info(struct platform_device *pdev)
                        pr_info(SYS "hdmitx_device.chip_type : %d\n",
                                hdmitx_device.chip_type);
 
+               ret = of_property_read_u32(pdev->dev.of_node,
+                       "repeater_tx", &val);
+               if (!ret)
+                       hdmitx_device.repeater_tx = val;
+               if (hdmitx_device.repeater_tx == 1)
+                       hdmitx_device.topo_info = kzalloc(
+                               sizeof(*hdmitx_device.topo_info), GFP_KERNEL);
+
                /* Get vendor information */
                ret = of_property_read_u32(pdev->dev.of_node,
                                "vend-data", &val);
@@ -4175,6 +4457,7 @@ static int amhdmitx_probe(struct platform_device *pdev)
        ret = device_create_file(dev, &dev_attr_dv_cap);
        ret = device_create_file(dev, &dev_attr_aud_ch);
        ret = device_create_file(dev, &dev_attr_avmute);
+       ret = device_create_file(dev, &dev_attr_swap);
        ret = device_create_file(dev, &dev_attr_vic);
        ret = device_create_file(dev, &dev_attr_phy);
        ret = device_create_file(dev, &dev_attr_frac_rate_policy);
@@ -4189,11 +4472,17 @@ static int amhdmitx_probe(struct platform_device *pdev)
        ret = device_create_file(dev, &dev_attr_hdcp_repeater);
        ret = device_create_file(dev, &dev_attr_hdcp_topo_info);
        ret = device_create_file(dev, &dev_attr_hdcp22_type);
+       ret = device_create_file(dev, &dev_attr_hdcp_stickmode);
+       ret = device_create_file(dev, &dev_attr_hdcp_stickstep);
+       ret = device_create_file(dev, &dev_attr_hdmi_repeater_tx);
        ret = device_create_file(dev, &dev_attr_hdcp22_base);
        ret = device_create_file(dev, &dev_attr_hdcp_lstore);
+       ret = device_create_file(dev, &dev_attr_hdcp_rptxlstore);
        ret = device_create_file(dev, &dev_attr_div40);
        ret = device_create_file(dev, &dev_attr_hdcp_ctrl);
        ret = device_create_file(dev, &dev_attr_hpd_state);
+       ret = device_create_file(dev, &dev_attr_rhpd_state);
+       ret = device_create_file(dev, &dev_attr_max_exceed);
        ret = device_create_file(dev, &dev_attr_hdmi_init);
        ret = device_create_file(dev, &dev_attr_ready);
        ret = device_create_file(dev, &dev_attr_support_3d);
@@ -4269,6 +4558,8 @@ static int amhdmitx_remove(struct platform_device *pdev)
        device_remove_file(dev, &dev_attr_dc_cap);
        device_remove_file(dev, &dev_attr_valid_mode);
        device_remove_file(dev, &dev_attr_hpd_state);
+       device_remove_file(dev, &dev_attr_rhpd_state);
+       device_remove_file(dev, &dev_attr_max_exceed);
        device_remove_file(dev, &dev_attr_hdmi_init);
        device_remove_file(dev, &dev_attr_ready);
        device_remove_file(dev, &dev_attr_support_3d);
@@ -4282,7 +4573,11 @@ static int amhdmitx_remove(struct platform_device *pdev)
        device_remove_file(dev, &dev_attr_hdcp_repeater);
        device_remove_file(dev, &dev_attr_hdcp_topo_info);
        device_remove_file(dev, &dev_attr_hdcp22_type);
+       device_remove_file(dev, &dev_attr_hdcp_stickmode);
+       device_remove_file(dev, &dev_attr_hdcp_stickstep);
+       device_remove_file(dev, &dev_attr_hdmi_repeater_tx);
        device_remove_file(dev, &dev_attr_hdcp22_base);
+       device_remove_file(dev, &dev_attr_swap);
 
        cdev_del(&hdmitx_device.cdev);
 
index c8abe65..4f3fe4d 100644 (file)
@@ -59,6 +59,14 @@ static void hdmitx_csc_config(unsigned char input_color_format,
 static int hdmitx_hdmi_dvi_config(struct hdmitx_dev *hdev,
        unsigned int dvi_mode);
 static void hdmitx_set_avi_colorimetry(struct hdmi_format_para *para);
+
+struct ksv_lists_ {
+       unsigned char valid;
+       unsigned int no;
+       unsigned char lists[MAX_KSV_LISTS * 5];
+};
+static struct ksv_lists_ tmp_ksv_lists;
+
 static void hdmitx_set_packet(int type, unsigned char *DB, unsigned char *HB);
 static void hdmitx_setaudioinfoframe(unsigned char *AUD_DB,
        unsigned char *CHAN_STAT_BUF);
@@ -91,16 +99,6 @@ static int hdmitx_cntl_misc(struct hdmitx_dev *hdev, unsigned int cmd,
 #define TX_INPUT_COLOR_RANGE   0
 /* Pixel bit width: 4=24-bit; 5=30-bit; 6=36-bit; 7=48-bit. */
 #define TX_COLOR_DEPTH          COLORDEPTH_24B
-
-/* store downstream ksv lists */
-static char *rptx_ksvs;
-static char rptx_ksv_prbuf[1271]; /* 127 * 5 * 2 + 1 */
-MODULE_PARM_DESC(rptx_ksvs, "\n downstream ksvs\n");
-module_param(rptx_ksvs, charp, 0444);
-static int rptx_ksv_no;
-static int rptx_ksvlist_retry;
-static char rptx_ksv_buf[635];
-
 int hdmitx_hpd_hw_op(enum hpd_op cmd)
 {
        struct hdmitx_dev *hdev = get_hdmitx_device();
@@ -244,6 +242,31 @@ static void config_avmute(unsigned int val)
        }
 }
 
+static int read_avmute(void)
+{
+       int val;
+       int ret = 0;
+
+       val = hdmitx_rd_reg(HDMITX_DWC_FC_GCP) & 0x3;
+
+       switch (val) {
+       case 2:
+               ret = 1;
+               break;
+       case 1:
+               ret = -1;
+               break;
+       case 0:
+               ret = 0;
+               break;
+       default:
+               ret = 3;
+               break;
+       }
+
+       return ret;
+}
+
 static void config_video_mapping(enum hdmi_color_space cs,
        enum hdmi_color_depth cd)
 {
@@ -438,6 +461,8 @@ static void hdmi_hwp_init(struct hdmitx_dev *hdev)
        /* assign phy_clk_en = control[1]; */
        /* Bring HDMITX MEM output of power down */
        hd_set_reg_bits(P_HHI_MEM_PD_REG0, 0, 8, 8);
+       /* enable CLK_TO_DIG */
+       hd_set_reg_bits(P_HHI_HDMI_PHY_CNTL3, 0x3, 0, 2);
        if (hdmitx_uboot_already_display()) {
                hdev->ready = 1;
                /* Get uboot output color space from AVI */
@@ -555,6 +580,10 @@ static void hdmi_hwi_init(struct hdmitx_dev *hdev)
        hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_HCNT_0, 0xcf);
        hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_LCNT_1, 0);
        hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_LCNT_0, 0xff);
+       if (hdev->repeater_tx == 1) {
+               hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_HCNT_0, 0x67);
+               hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_LCNT_0, 0x78);
+       }
        hdmitx_wr_reg(HDMITX_DWC_I2CM_FS_SCL_HCNT_1, 0);
        hdmitx_wr_reg(HDMITX_DWC_I2CM_FS_SCL_HCNT_0, 0x0f);
        hdmitx_wr_reg(HDMITX_DWC_I2CM_FS_SCL_LCNT_1, 0);
@@ -587,60 +616,63 @@ void HDMITX_Meson_Init(struct hdmitx_dev *hdev)
        hdmi_hwp_init(hdev);
        hdmi_hwi_init(hdev);
        hdev->HWOp.CntlMisc(hdev, MISC_AVMUTE_OP, CLR_AVMUTE);
-       rptx_ksvs = &rptx_ksv_prbuf[0];
 }
 
 static irqreturn_t intr_handler(int irq, void *dev)
 {
-       unsigned int data32 = 0;
+       /* get interrupt status */
+       unsigned int dat_top = hdmitx_rd_reg(HDMITX_TOP_INTR_STAT);
+       unsigned int dat_dwc = hdmitx_rd_reg(HDMITX_DWC_HDCP22REG_STAT);
        struct hdmitx_dev *hdev = (struct hdmitx_dev *)dev;
 
-       /* get interrupt status */
-       data32 = hdmitx_rd_reg(HDMITX_TOP_INTR_STAT);
-       pr_info(HW "irq %x\n", data32);
+       /* ack INTERNAL_INTR or else we stuck with no interrupts at all */
+       hdmitx_wr_reg(HDMITX_TOP_INTR_STAT_CLR, ~0);
+       hdmitx_wr_reg(HDMITX_DWC_HDCP22REG_STAT, 0xff);
+
+       pr_info(SYS "irq %x\n", dat_top);
+       if (dat_dwc)
+               pr_info(SYS "irq %x\n", dat_dwc);
        if (hdev->hpd_lock == 1) {
-               hdmitx_wr_reg(HDMITX_TOP_INTR_STAT_CLR, 0xf);
                pr_info(HW "HDMI hpd locked\n");
                goto next;
        }
        /* check HPD status */
-       if ((data32 & (1 << 1)) && (data32 & (1 << 2))) {
+       if ((dat_top & (1 << 1)) && (dat_top & (1 << 2))) {
                if (hdmitx_hpd_hw_op(HPD_READ_HPD_GPIO))
-                       data32 &= ~(1 << 2);
+                       dat_top &= ~(1 << 2);
                else
-                       data32 &= ~(1 << 1);
+                       dat_top &= ~(1 << 1);
        }
        /* HPD rising */
-       if (data32 & (1 << 1)) {
+       if (dat_top & (1 << 1)) {
                hdev->hdmitx_event |= HDMI_TX_HPD_PLUGIN;
                hdev->hdmitx_event &= ~HDMI_TX_HPD_PLUGOUT;
+               hdev->rhpd_state = 1;
                queue_delayed_work(hdev->hdmi_wq,
                        &hdev->work_hpd_plugin, HZ / 2);
        }
        /* HPD falling */
-       if (data32 & (1 << 2)) {
+       if (dat_top & (1 << 2)) {
                queue_delayed_work(hdev->hdmi_wq,
                        &hdev->work_aud_hpd_plug, 2 * HZ);
                hdev->hdmitx_event |= HDMI_TX_HPD_PLUGOUT;
                hdev->hdmitx_event &= ~HDMI_TX_HPD_PLUGIN;
+               hdev->rhpd_state = 0;
                queue_delayed_work(hdev->hdmi_wq,
                        &hdev->work_hpd_plugout, HZ / 20);
        }
-next:
        /* internal interrupt */
-       if (data32 & (1 << 0)) {
+       if (dat_top & (1 << 0)) {
                hdev->hdmitx_event |= HDMI_TX_INTERNAL_INTR;
                queue_work(hdev->hdmi_wq, &hdev->work_internal_intr);
        }
-       if (data32 & (1 << 3)) {
+       if (dat_top & (1 << 3)) {
                unsigned int rd_nonce_mode =
                        hdmitx_rd_reg(HDMITX_TOP_SKP_CNTL_STAT) & 0x1;
                pr_info(HW "hdcp22: Nonce %s  Vld: %d\n",
                        rd_nonce_mode ? "HW" : "SW",
                        ((hdmitx_rd_reg(HDMITX_TOP_SKP_CNTL_STAT) >> 31) & 1));
-               if (rd_nonce_mode)
-                       hdmitx_wr_reg(HDMITX_TOP_INTR_STAT_CLR, (1 << 3));
-               else {
+               if (!rd_nonce_mode) {
                        hdmitx_wr_reg(HDMITX_TOP_NONCE_0,  0x32107654);
                        hdmitx_wr_reg(HDMITX_TOP_NONCE_1,  0xba98fedc);
                        hdmitx_wr_reg(HDMITX_TOP_NONCE_2,  0xcdef89ab);
@@ -651,13 +683,10 @@ next:
                        hdmitx_wr_reg(HDMITX_TOP_NONCE_3,  0x01234567);
                }
        }
-       if (data32 & (1 << 30)) {
-               pr_info(HW "hdcp22: reg stat: 0x%x\n",
-                       hdmitx_rd_reg(HDMITX_DWC_HDCP22REG_STAT));
-               hdmitx_wr_reg(HDMITX_DWC_HDCP22REG_STAT, 0xff);
-       }
-       /* ack INTERNAL_INTR or else we stuck with no interrupts at all */
-       hdmitx_wr_reg(HDMITX_TOP_INTR_STAT_CLR, data32 | 0x7);
+       if (dat_top & (1 << 30))
+               pr_info("hdcp22: reg stat: 0x%x\n", dat_dwc);
+
+next:
        return IRQ_HANDLED;
 }
 
@@ -2318,8 +2347,14 @@ static void set_aud_samp_pkt(struct hdmitx_dev *hdev,
        }
 }
 
+static int amute_flag = -1;
 static void audio_mute_op(bool flag)
 {
+       if (amute_flag != flag)
+               amute_flag = flag;
+       else
+               return;
+
        if (flag == 0) {
                hdmitx_set_reg_bits(HDMITX_TOP_CLK_CNTL, 0, 2, 2);
                hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 0, 0, 1);
@@ -4093,8 +4128,6 @@ static void hdmitx_read_edid(unsigned char *rx_edid)
        }
 } /* hdmi20_tx_read_edid */
 
-#define HDCP_NMOOFDEVICES 127
-
 static int get_hdcp_depth(void)
 {
        int ret;
@@ -4143,68 +4176,54 @@ static int get_hdcp_device_count(void)
        return ret;
 }
 
-static void get_hdcp_bstatus(void)
+static void get_hdcp_bstatus(int *ret1, int *ret2)
 {
-       int ret1 = 0;
-       int ret2 = 0;
-
        hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 1, 0, 1);
        hdmitx_poll_reg(HDMITX_DWC_A_KSVMEMCTRL, (1<<1), 2 * HZ);
-       ret1 = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_0);
-       ret2 = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_1);
+       *ret1 = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_0);
+       *ret2 = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_1);
        hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 0, 1);
-       pr_info("BSTATUS0 = 0x%x   BSTATUS1 = 0x%x\n", ret1, ret2);
 }
 
-static void hdcp_ksv_store(unsigned char *dat, int no)
+static void hdcp_ksv_store(struct hdcprp_topo *topo,
+       unsigned char *dat, int no)
 {
        int i;
+       int pos;
 
-       for (i = 0; i < no; i++) {
-               rptx_ksv_buf[rptx_ksv_no] = dat[i];
-               rptx_ksv_no++;
-       }
-}
-
-static void hdcp_ksv_print(void)
-{
-       unsigned int i, pos;
-       unsigned char *tmp_buf = NULL;
-
-       tmp_buf = kmalloc(2000, GFP_ATOMIC);
-       if (!tmp_buf)
+       if (!topo)
+               return;
+       if (topo->hdcp_ver != 1)
+               return;
+       /* must check ksv num to prevent leak */
+       if (topo->topo.topo14.device_count >= MAX_KSV_LISTS)
                return;
 
-       pos = 0;
-       memset(tmp_buf, 0, sizeof(2000));
-       pos += sprintf(tmp_buf + pos, "Dump ksv test START\n");
-       for (i = 0; (i < rptx_ksv_no) && (i < 635); i++) {
-               pos += sprintf(tmp_buf + pos, "%02x", rptx_ksv_buf[i]);
-               if (((i+1) % 40) == 0)    /* print 40bytes a line */
-                       pos += sprintf(tmp_buf + pos, "\n");
-       }
-       pos += sprintf(tmp_buf + pos, "\n");
-       pos += sprintf(tmp_buf + pos, "Dump ksv test END\n");
-       pr_info("%s\n", tmp_buf);
-       kfree(tmp_buf);
+       pos = topo->topo.topo14.device_count * 5;
+       for (i = 0; (i < no) && (i < MAX_KSV_LISTS * 5); i++)
+               topo->topo.topo14.ksv_list[pos++] = dat[i];
+       topo->topo.topo14.device_count += no / 5;
 }
 
 static uint8_t *hdcp_mKsvListBuf;
+static int ksv_sha_matched;
 static void hdcp_ksv_sha1_calc(struct hdmitx_dev *hdev)
 {
        size_t list = 0;
        size_t size = 0;
        size_t i = 0;
        int valid = HDCP_NULL;
-       unsigned char ksvs[635] = {0}; /* Max 127 * 5 */
+       char temp[MAX_KSV_LISTS * 5];
        int j = 0;
 
        /* 0x165e: Page 95 */
+       memset(&tmp_ksv_lists, 0, sizeof(tmp_ksv_lists));
+       memset(&temp[0], 0, sizeof(temp));
        hdcp_mKsvListBuf = kmalloc(0x1660, GFP_ATOMIC);
        if (hdcp_mKsvListBuf) {
                /* KSV_SIZE; */
                list = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_0) & KSV_MASK;
-               if (list <= HDCP_NMOOFDEVICES) {
+               if (list <= MAX_KSV_LISTS) {
                        size = (list * KSV_SIZE) + HDCP_HEAD + SHA_MAX_SIZE;
                        for (i = 0; i < size; i++) {
                                if (i < HDCP_HEAD) { /* BSTATUS & M0 */
@@ -4217,9 +4236,11 @@ static void hdcp_ksv_sha1_calc(struct hdmitx_dev *hdev)
                                        hdcp_mKsvListBuf[i - HDCP_HEAD] =
                                                hdmitx_rd_reg(
                                                HDMITX_DWC_HDCP_BSTATUS_0 + i);
-                                       ksvs[j] =
+                                       tmp_ksv_lists.lists[tmp_ksv_lists.no++]
+                                               = hdcp_mKsvListBuf[i -
+                                                       HDCP_HEAD];
+                                       temp[j++] =
                                                hdcp_mKsvListBuf[i - HDCP_HEAD];
-                                       j++;
                                } else { /* SHA */
                                        hdcp_mKsvListBuf[i] = hdmitx_rd_reg(
                                                HDMITX_DWC_HDCP_BSTATUS_0 + i);
@@ -4229,12 +4250,18 @@ static void hdcp_ksv_sha1_calc(struct hdmitx_dev *hdev)
                                valid = HDCP_KSVLIST_VALID;
                        else
                                valid = HDCP_KSVLIST_INVALID;
+                       ksv_sha_matched = valid;
                }
                hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 0, 1);
                hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL,
                        (valid == HDCP_KSVLIST_VALID) ? 0 : 1, 3, 1);
-               if (valid == HDCP_KSVLIST_VALID)
-                       hdcp_ksv_store(ksvs, j);
+               if (valid == HDCP_KSVLIST_VALID) {
+                       tmp_ksv_lists.valid = 1;
+                       for (i = 0; (i < j) &&
+                               (tmp_ksv_lists.no < MAX_KSV_LISTS * 5); i++)
+                               tmp_ksv_lists.lists[tmp_ksv_lists.no++]
+                                       = temp[i];
+               }
                hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 1, 2, 1);
                hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 2, 1);
                kfree(hdcp_mKsvListBuf);
@@ -4242,15 +4269,50 @@ static void hdcp_ksv_sha1_calc(struct hdmitx_dev *hdev)
                pr_info("hdcptx14: KSV List memory not valid\n");
 }
 
+static int max_exceed = 200;
+MODULE_PARM_DESC(max_exceed, "\nmax_exceed\n");
+module_param(max_exceed, int, 0664);
+
 static void hdcptx_events_handle(unsigned long arg)
 {
        struct hdmitx_dev *hdev = (struct hdmitx_dev *)arg;
        unsigned char ksv[5] = {0};
-       int pos, i;
+       int i;
        unsigned int bcaps_6_rp;
+       static unsigned int bcaps_5_ksvfifoready;
        static unsigned int st_flag = -1;
+       static unsigned int hdcpobs3_1;
+       unsigned int hdcpobs3_2;
+       struct hdcprp14_topo *topo14 = &hdev->topo_info->topo.topo14;
+       int bstatus0 = 0;
+       int bstatus1 = 0;
+
+       if (hdev->hdcp_max_exceed_cnt == 0) {
+               hdcpobs3_1 = 0;
+               bcaps_5_ksvfifoready = 0;
+       }
+
+       hdcpobs3_2 = hdmitx_rd_reg(HDMITX_DWC_A_HDCPOBS3);
+       if (hdcpobs3_1 != hdcpobs3_2)
+               hdcpobs3_1 = hdcpobs3_2;
+
+       bcaps_6_rp = !!(hdcpobs3_1 & (1 << 6));
+       bcaps_5_ksvfifoready = !!(hdcpobs3_1 & (1 << 5));
+
+       if (bcaps_6_rp && bcaps_5_ksvfifoready
+               && (hdev->hdcp_max_exceed_cnt == 0))
+               hdev->hdcp_max_exceed_cnt++;
+       if (hdev->hdcp_max_exceed_cnt)
+               hdev->hdcp_max_exceed_cnt++;
+       if (bcaps_6_rp && bcaps_5_ksvfifoready) {
+               if ((hdev->hdcp_max_exceed_cnt > max_exceed)
+                       && !ksv_sha_matched) {
+                       topo14->max_devs_exceeded = 1;
+                       topo14->max_cascade_exceeded = 1;
+                       hdev->hdcp_max_exceed_state = 1;
+               }
+       }
 
-       bcaps_6_rp = !!(hdmitx_rd_reg(HDMITX_DWC_A_HDCPOBS3) & (1 << 6));
        if (st_flag != hdmitx_rd_reg(HDMITX_DWC_A_APIINTSTAT)) {
                st_flag = hdmitx_rd_reg(HDMITX_DWC_A_APIINTSTAT);
                pr_info("hdcp14: instat: 0x%x\n", st_flag);
@@ -4258,27 +4320,43 @@ static void hdcptx_events_handle(unsigned long arg)
        if (st_flag & (1 << 7)) {
                hdmitx_wr_reg(HDMITX_DWC_A_APIINTCLR, 1 << 7);
                hdmitx_hdcp_opr(3);
+               if (bcaps_6_rp)
+                       get_hdcp_bstatus(&bstatus0, &bstatus1);
                for (i = 0; i < 5; i++)
                        ksv[i] = (unsigned char)
                                hdmitx_rd_reg(HDMITX_DWC_HDCPREG_BKSV0 + i);
-               hdcp_ksv_store(ksv, 5);
-               get_hdcp_bstatus();
-               if (hdev->repeater_tx) {
-                       rx_set_receive_hdcp(rptx_ksv_buf, (rptx_ksv_no + 1) / 5,
-                               (bcaps_6_rp ? get_hdcp_depth() : 0) + 1,
-                               bcaps_6_rp ? get_hdcp_max_cascade() : 0,
-                               bcaps_6_rp ? get_hdcp_max_devs() : 0);
-                       pr_info("%s[%d]  ksvs Num = %d  device_count = %d\n",
-                               __func__, __LINE__,
-                               (rptx_ksv_no + 1) / 5,
-                               bcaps_6_rp ? get_hdcp_device_count() : 0);
-                       memset(rptx_ksv_prbuf, 0, sizeof(rptx_ksv_prbuf));
-                               for (pos = 0, i = 0; i < rptx_ksv_no; i++)
-                                       pos += sprintf(rptx_ksv_prbuf + pos,
-                                               "%02x", rptx_ksv_buf[i]);
-                               rptx_ksv_prbuf[pos + 1] = '\0';
-                       if (1)
-                               hdcp_ksv_print();
+               /* if downstream is only RX */
+               if ((hdev->repeater_tx == 1) && hdev->topo_info) {
+                       hdcp_ksv_store(hdev->topo_info, ksv, 5);
+                       if (tmp_ksv_lists.valid) {
+                               int cnt = get_hdcp_device_count();
+                               int devs = get_hdcp_max_devs();
+                               int cascade = get_hdcp_max_cascade();
+                               int depth = get_hdcp_depth();
+
+                               hdcp_ksv_store(hdev->topo_info,
+                                       tmp_ksv_lists.lists, tmp_ksv_lists.no);
+                               if (cnt >= 127) {
+                                       topo14->device_count = 127;
+                                       topo14->max_devs_exceeded = 1;
+                               } else {
+                                       topo14->device_count = cnt + 1;
+                                       topo14->max_devs_exceeded = devs;
+                               }
+
+                               if (depth >= 7) {
+                                       topo14->depth = 7;
+                                       topo14->max_cascade_exceeded = 1;
+                               } else {
+                                       topo14->depth = depth + 1;
+                                       topo14->max_cascade_exceeded = cascade;
+                               }
+                       } else {
+                               topo14->device_count = 1;
+                               topo14->max_devs_exceeded = 0;
+                               topo14->max_cascade_exceeded = 0;
+                               topo14->depth = 1;
+                       }
                }
        }
        if (st_flag & (1 << 1)) {
@@ -4292,30 +4370,8 @@ static void hdcptx_events_handle(unsigned long arg)
                        return;
                }
                hdmitx_wr_reg(HDMITX_DWC_A_KSVMEMCTRL, 0x4);
-               if (hdev->repeater_tx) {
-                       rptx_ksvlist_retry++;
-                       if (rptx_ksvlist_retry % 4 == 0) {
-                               for (i = 0; i < 5; i++)
-                                       ksv[i] = (unsigned char) hdmitx_rd_reg(
-                                               HDMITX_DWC_HDCPREG_BKSV0 + i);
-                               hdcp_ksv_store(ksv, 5);
-                               rx_set_receive_hdcp(&ksv[0], 1, 127, 1, 1);
-                       }
-               }
        }
-       if (hdev->repeater_tx && bcaps_6_rp && (get_hdcp_max_devs() ||
-               get_hdcp_max_cascade())) {
-               for (i = 0; i < 5; i++)
-                       ksv[i] = (unsigned char)
-                               hdmitx_rd_reg(HDMITX_DWC_HDCPREG_BKSV0 + i);
-               hdcp_ksv_store(ksv, 5);
-               rx_set_receive_hdcp(&ksv[0], 1, 127, 1, 1);
-       }
-       if (hdev->hdcp_try_times)
-               mod_timer(&hdev->hdcp_timer, jiffies + HZ / 100);
-       else
-               return;
-       hdev->hdcp_try_times--;
+       mod_timer(&hdev->hdcp_timer, jiffies + HZ / 100);
 }
 
 static void hdcp_start_timer(struct hdmitx_dev *hdev)
@@ -4329,10 +4385,8 @@ static void hdcp_start_timer(struct hdmitx_dev *hdev)
                hdev->hdcp_timer.function = hdcptx_events_handle;
                hdev->hdcp_timer.expires = jiffies + HZ / 100;
                add_timer(&hdev->hdcp_timer);
-               hdev->hdcp_try_times = 500;
                return;
        }
-       hdev->hdcp_try_times = 500;
        hdev->hdcp_timer.expires = jiffies + HZ / 100;
        mod_timer(&hdev->hdcp_timer, jiffies + HZ / 100);
 }
@@ -4362,6 +4416,20 @@ static void set_pkf_duk_nonce(void)
        udelay(10);
 }
 
+static void check_read_ksv_list_st(void)
+{
+       int cnt = 0;
+
+       for (cnt = 0; cnt < 5; cnt++) {
+               if (((hdmitx_rd_reg(HDMITX_DWC_A_HDCPOBS1) & 0x7) == 5) ||
+                   ((hdmitx_rd_reg(HDMITX_DWC_A_HDCPOBS1) & 0x7) == 6))
+                       msleep(20);
+               else
+                       return;
+       }
+       pr_info("hdcp14: FSM: A9 read ksv list\n");
+}
+
 static int hdmitx_cntl_ddc(struct hdmitx_dev *hdev, unsigned int cmd,
        unsigned long argv)
 {
@@ -4421,22 +4489,33 @@ static int hdmitx_cntl_ddc(struct hdmitx_dev *hdev, unsigned int cmd,
                }
                if (argv == 1)
                        hdmitx_hdcp_opr(6);
+               if (argv == 3)
+                       hdmitx_set_reg_bits(HDMITX_DWC_HDCP22REG_CTRL, 1, 2, 1);
                break;
        case DDC_HDCP_OP:
+               hdev->hdcp_max_exceed_state = 0;
+               hdev->hdcp_max_exceed_cnt = 0;
+               ksv_sha_matched = 0;
+               del_timer(&hdev->hdcp_timer);
+               if (hdev->topo_info)
+                       memset(hdev->topo_info, 0, sizeof(*hdev->topo_info));
+
                if (argv == HDCP14_ON) {
-                       rptx_ksvlist_retry = 0;
-                       rptx_ksv_no = 0;
-                       memset(rptx_ksv_buf, 0, sizeof(rptx_ksv_buf));
+                       check_read_ksv_list_st();
+                       if (hdev->topo_info)
+                               hdev->topo_info->hdcp_ver = HDCPVER_14;
                        hdmitx_ddc_hw_op(DDC_MUX_DDC);
+                       hdmitx_set_reg_bits(HDMITX_TOP_SKP_CNTL_STAT, 0, 3, 1);
+                       hdmitx_set_reg_bits(HDMITX_TOP_CLK_CNTL, 1, 31, 1);
                        hdmitx_hdcp_opr(6);
                        hdmitx_hdcp_opr(1);
                        hdcp_start_timer(hdev);
                }
-               if (argv == HDCP14_OFF) {
-                       rptx_ksvlist_retry = 0;
+               if (argv == HDCP14_OFF)
                        hdmitx_hdcp_opr(4);
-               }
                if (argv == HDCP22_ON) {
+                       if (hdev->topo_info)
+                               hdev->topo_info->hdcp_ver = 2;
                        hdmitx_ddc_hw_op(DDC_MUX_DDC);
                        hdmitx_hdcp_opr(5);
                        /* wait for start hdcp22app */
@@ -4444,6 +4523,9 @@ static int hdmitx_cntl_ddc(struct hdmitx_dev *hdev, unsigned int cmd,
                if (argv == HDCP22_OFF)
                        hdmitx_hdcp_opr(6);
                break;
+       case DDC_IS_HDCP_ON:
+/* argv = !!((hdmitx_rd_reg(TX_HDCP_MODE)) & (1 << 7)); */
+               break;
        case DDC_HDCP_GET_BKSV:
                tmp_char = (unsigned char *) argv;
                for (i = 0; i < 5; i++)
@@ -4652,6 +4734,8 @@ static int hdmitx_tmds_rxsense(void)
 static int hdmitx_cntl_misc(struct hdmitx_dev *hdev, unsigned int cmd,
        unsigned int argv)
 {
+       static int st;
+
        if ((cmd & CMD_MISC_OFFSET) != CMD_MISC_OFFSET) {
                pr_err(HW "misc: w: invalid cmd 0x%x\n", cmd);
                return -1;
@@ -4692,16 +4776,24 @@ static int hdmitx_cntl_misc(struct hdmitx_dev *hdev, unsigned int cmd,
        case MISC_AVMUTE_OP:
                config_avmute(argv);
                break;
+       case MISC_READ_AVMUTE_OP:
+               return read_avmute();
        case MISC_HDCP_CLKDIS:
+               if (st != !!argv) {
+                       st = !!argv;
+                       pr_info("set hdcp clkdis: %d\n", !!argv);
+               }
                hdmitx_set_reg_bits(HDMITX_DWC_MC_CLKDIS, !!argv, 6, 1);
                break;
        case MISC_I2C_REACTIVE:
+               hdmitx_hdcp_opr(4);
                hdmitx_set_reg_bits(HDMITX_DWC_A_HDCPCFG1, 0, 0, 1);
                hdmitx_set_reg_bits(HDMITX_DWC_HDCP22REG_CTRL, 0, 2, 1);
                hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_HCNT_1, 0xff);
                hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_HCNT_0, 0xf6);
                edid_read_head_8bytes();
                hdmi_hwi_init(hdev);
+               mdelay(5);
                break;
        default:
                break;
@@ -4777,7 +4869,10 @@ static int hdmitx_get_state(struct hdmitx_dev *hdev, unsigned int cmd,
 static void hdmi_phy_suspend(void)
 {
        hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x0);
-       hd_write_reg(P_HHI_HDMI_PHY_CNTL3, 0x0);
+       /* keep PHY_CNTL3 bit[1:0] as 0b11,
+        * otherwise may cause HDCP22 boot failed
+        */
+       hd_write_reg(P_HHI_HDMI_PHY_CNTL3, 0x3);
        hd_write_reg(P_HHI_HDMI_PHY_CNTL5, 0x800);
 }
 
@@ -5194,7 +5289,8 @@ static void config_hdmi20_tx(enum hdmi_vic vic,
        data32 |= (default_phase << 2);
        data32 |= (0 << 1);
        data32 |= (0 << 0);
-       hdmitx_wr_reg(HDMITX_DWC_FC_GCP, data32);
+       if (!hdev->repeater_tx)
+               hdmitx_wr_reg(HDMITX_DWC_FC_GCP, data32);
 
        /* write AVI Infoframe packet configuration */
        data32  = 0;
index b028ec2..e143e27 100644 (file)
@@ -131,42 +131,6 @@ enum hdcp_authstate {
        HDCP_MAX
 };
 
-enum hdcp_ver_e {
-       HDCPVER_NONE = 0,
-       HDCPVER_14,
-       HDCPVER_22,
-};
-
-#define HDCP14_MAX_KSV_LISTS 127
-struct hdcprp14_topo {
-       unsigned char max_cascade_exceeded:1;
-       unsigned char depth:3;
-       unsigned char max_devs_exceeded:1;
-       unsigned char device_count:7; /* 1 ~ 127 */
-       unsigned char ksv_list[HDCP14_MAX_KSV_LISTS * 5];
-};
-
-#define HDCP22_MAX_KSV_LISTS 31
-struct hdcprp22_topo {
-       int depth;
-       int device_count;
-       int v1_X_device_down;
-       int v2_0_repeater_down;
-       int max_devs_exceeded;
-       int max_cascade_exceeded;
-       unsigned char id_num;
-       unsigned char id_lists[HDCP22_MAX_KSV_LISTS * 5];
-};
-
-struct hdcprp_topo {
-       /* hdcp_ver currently used */
-       enum hdcp_ver_e hdcp_ver;
-       union {
-               struct hdcprp14_topo topo14;
-               struct hdcprp22_topo topo22;
-       } topo;
-};
-
 /* -----------------------HDCP END---------------------------------------- */
 
 /* -----------------------HDMI TX---------------------------------- */
diff --git a/include/linux/amlogic/media/vout/hdmi_tx/hdmi_rptx.h b/include/linux/amlogic/media/vout/hdmi_tx/hdmi_rptx.h
new file mode 100644 (file)
index 0000000..3b1d981
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * include/linux/amlogic/media/vout/hdmi_tx/hdmi_rptx.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef _HDMI_RPTX_H_
+#define _HDMI_RPTX_H_
+
+enum rptx_hdcp14_cmd {
+       RPTX_HDCP14_OFF,
+       RPTX_HDCP14_ON,
+       RPTX_HDCP14_GET_AUTHST,
+};
+
+extern void direct_hdcptx14_opr(enum rptx_hdcp14_cmd cmd, void *args);
+
+#endif
index 366e204..5ef3d54 100644 (file)
@@ -65,6 +65,12 @@ struct rx_audiocap {
        unsigned char cc3;
 };
 
+#define MAX_RAW_LEN 64
+struct raw_block {
+       int len;
+       char raw[MAX_RAW_LEN];
+};
+
 enum hd_ctrl {
        VID_EN, VID_DIS, AUD_EN, AUD_DIS, EDID_EN, EDID_DIS, HDCP_EN, HDCP_DIS,
 };
@@ -145,6 +151,8 @@ struct rx_cap {
        unsigned char dtd_idx;
        unsigned char flag_vfpdb;
        unsigned char number_of_dtd;
+       struct raw_block asd;
+       struct raw_block vsd;
        /*blk0 check sum*/
        unsigned char blk0_chksum;
 };
@@ -232,6 +240,48 @@ struct hdmitx_clk_tree_s {
        struct clk *venci_1_gate;
 };
 
+/* 2kB should be enough to record */
+#define HDCP_LOG_SIZE (1024 * 2)
+struct hdcplog_buf {
+       int idx;
+       unsigned char buf[HDCP_LOG_SIZE + 64]; /* padding 8 bytes */
+};
+
+enum hdcp_ver_e {
+       HDCPVER_NONE = 0,
+       HDCPVER_14,
+       HDCPVER_22,
+};
+
+#define MAX_KSV_LISTS 127
+struct hdcprp14_topo {
+       unsigned char max_cascade_exceeded:1;
+       unsigned char depth:3;
+       unsigned char max_devs_exceeded:1;
+       unsigned char device_count:7; /* 1 ~ 127 */
+       unsigned char ksv_list[MAX_KSV_LISTS * 5];
+};
+
+struct hdcprp22_topo {
+       unsigned int depth;
+       unsigned int device_count;
+       unsigned int v1_X_device_down;
+       unsigned int v2_0_repeater_down;
+       unsigned int max_devs_exceeded;
+       unsigned int max_cascade_exceeded;
+       unsigned char id_num;
+       unsigned char id_lists[MAX_KSV_LISTS * 5];
+};
+
+struct hdcprp_topo {
+       /* hdcp_ver currently used */
+       enum hdcp_ver_e hdcp_ver;
+       union {
+               struct hdcprp14_topo topo14;
+               struct hdcprp22_topo topo22;
+       } topo;
+};
+
 #define EDID_MAX_BLOCK              4
 #define HDMI_TMP_BUF_SIZE           1024
 struct hdmitx_dev {
@@ -259,7 +309,6 @@ struct hdmitx_dev {
        struct delayed_work cec_work;
 #endif
        struct timer_list hdcp_timer;
-       int hdcp_try_times;
        int chip_type;
        int hdmi_init;
        int hpdmode;
@@ -269,7 +318,6 @@ struct hdmitx_dev {
        int ready;      /* 1, hdmi stable output, others are 0 */
        int hdcp_hpd_stick;     /* 1 not init & reset at plugout */
        int hdcp_tst_sig;
-       bool hdcp22_type;
        unsigned int div40;
        unsigned int lstore;
        struct {
@@ -335,6 +383,9 @@ struct hdmitx_dev {
        /**/
        unsigned char hpd_event; /* 1, plugin; 2, plugout */
        unsigned char hpd_state; /* 1, connect; 0, disconnect */
+       unsigned char rhpd_state; /* For repeater use only, no delay */
+       unsigned char hdcp_max_exceed_state;
+       unsigned int hdcp_max_exceed_cnt;
        unsigned char force_audio_flag;
        unsigned char mux_hpd_if_pin_high_flag;
        int auth_process_timer;
@@ -352,6 +403,7 @@ struct hdmitx_dev {
        unsigned int output_blank_flag;
        unsigned int audio_notify_flag;
        unsigned int audio_step;
+       bool hdcp22_type;
        unsigned int repeater_tx;
        struct hdcprp_topo *topo_info;
        /* 0.1% clock shift, 1080p60hz->59.94hz */
@@ -401,6 +453,7 @@ struct hdmitx_dev {
        #define HDCP14_OFF      0x2
        #define HDCP22_ON       0x3
        #define HDCP22_OFF      0x4
+#define DDC_IS_HDCP_ON          (CMD_DDC_OFFSET + 0x04)
 #define DDC_HDCP_GET_AKSV       (CMD_DDC_OFFSET + 0x05)
 #define DDC_HDCP_GET_BKSV       (CMD_DDC_OFFSET + 0x06)
 #define DDC_HDCP_GET_AUTH       (CMD_DDC_OFFSET + 0x07)
@@ -408,6 +461,7 @@ struct hdmitx_dev {
 #define PIN_MUX             0x1
 #define PIN_UNMUX           0x2
 #define DDC_EDID_READ_DATA      (CMD_DDC_OFFSET + 0x0a)
+#define DDC_IS_EDID_DATA_READY  (CMD_DDC_OFFSET + 0x0b)
 #define DDC_EDID_GET_DATA       (CMD_DDC_OFFSET + 0x0c)
 #define DDC_EDID_CLEAR_RAM      (CMD_DDC_OFFSET + 0x0d)
 #define DDC_HDCP_MUX_INIT      (CMD_DDC_OFFSET + 0x0e)
@@ -417,6 +471,7 @@ struct hdmitx_dev {
 #define DDC_HDCP14_GET_BCAPS_RP        (CMD_DDC_OFFSET + 0x30)
 #define DDC_HDCP14_GET_TOPO_INFO (CMD_DDC_OFFSET + 0x31)
 #define DDC_HDCP_SET_TOPO_INFO (CMD_DDC_OFFSET + 0x32)
+#define DDC_HDCP14_SAVE_OBS    (CMD_DDC_OFFSET + 0x40)
 
 /***********************************************************************
  *             CONFIG CONTROL //CntlConfig
@@ -487,6 +542,7 @@ struct hdmitx_dev {
 #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_READ_AVMUTE_OP     (CMD_MISC_OFFSET + 0x11)
 
 /***********************************************************************
  *                          Get State //GetState
@@ -574,16 +630,6 @@ void __attribute__((weak))rx_set_receiver_edid(unsigned char *data, int len)
 {
 }
 
-/*
- * ver = 22 means downstream supports HDCP22
- * ver = 14 means support HDCP14
- * ver = 0 means support NO HDCP
- */
-extern void rx_repeat_hdcp_ver(unsigned int ver);
-void __attribute__((weak))rx_repeat_hdcp_ver(unsigned int ver)
-{
-}
-
 extern void rx_set_receive_hdcp(unsigned char *data, int len, int depth,
        bool max_cascade, bool max_devs);
 void __attribute__((weak))rx_set_receive_hdcp(unsigned char *data, int len,