hdmitx: add hdcp topo information [3/5]
authorZongdong Jiao <zongdong.jiao@amlogic.com>
Thu, 24 May 2018 08:16:11 +0000 (16:16 +0800)
committerZongdong Jiao <zongdong.jiao@amlogic.com>
Sat, 26 May 2018 08:25:57 +0000 (16:25 +0800)
PD#165815: hdmitx: add hdcp topo information

1. add SYSFS 'hdcp_topo_info' to represent HDCP22 Topology
2. rewrite SYSFS 'hdcp22_type', should be controlled by Daemon

Change-Id: Ie9f748c5592a32b8658b63186429794e877fd41c
Signed-off-by: Zongdong Jiao <zongdong.jiao@amlogic.com>
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_tx_module.h

index 9e22725..280df7f 100644 (file)
@@ -928,6 +928,94 @@ static ssize_t store_hdcp_repeater(struct device *dev,
        return count;
 }
 
+/*
+ * hdcp_topo_info attr
+ * For hdcp 22, hdcp_tx22 will write to store_hdcp_topo_info
+ * For hdcp 14, directly get from HW
+ */
+
+static ssize_t show_hdcp_topo_info(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       int pos = 0;
+       struct hdmitx_dev *hdev = &hdmitx_device;
+       struct hdcprp_topo *topoinfo = hdev->topo_info;
+
+       if (!hdev->hdcp_mode) {
+               pos += snprintf(buf+pos, PAGE_SIZE, "hdcp mode: 0\n");
+               return pos;
+       }
+       if (!topoinfo)
+               return pos;
+
+       if (hdev->hdcp_mode == 1) {
+               memset(topoinfo, 0, sizeof(struct hdcprp_topo));
+               hdev->HWOp.CntlDDC(hdev, DDC_HDCP14_GET_TOPO_INFO,
+                       (unsigned long)&topoinfo->topo.topo14);
+       }
+
+       pos += snprintf(buf+pos, PAGE_SIZE, "hdcp mode: %s\n",
+               hdev->hdcp_mode == 1 ? "14" : "22");
+       if (hdev->hdcp_mode == 2) {
+               topoinfo->hdcp_ver = HDCPVER_22;
+               pos += snprintf(buf+pos, PAGE_SIZE, "max_devs_exceeded: %d\n",
+                       topoinfo->topo.topo22.max_devs_exceeded);
+               pos += snprintf(buf+pos, PAGE_SIZE,
+                       "max_cascade_exceeded: %d\n",
+                       topoinfo->topo.topo22.max_cascade_exceeded);
+               pos += snprintf(buf+pos, PAGE_SIZE, "v2_0_repeater_down: %d\n",
+                       topoinfo->topo.topo22.v2_0_repeater_down);
+               pos += snprintf(buf+pos, PAGE_SIZE, "v1_X_device_down: %d\n",
+                       topoinfo->topo.topo22.v1_X_device_down);
+               pos += snprintf(buf+pos, PAGE_SIZE, "device_count: %d\n",
+                       topoinfo->topo.topo22.device_count);
+               pos += snprintf(buf+pos, PAGE_SIZE, "depth: %d\n",
+                       topoinfo->topo.topo22.depth);
+               return pos;
+       }
+       if (hdev->hdcp_mode == 1) {
+               topoinfo->hdcp_ver = HDCPVER_14;
+               pos += snprintf(buf+pos, PAGE_SIZE, "max_devs_exceeded: %d\n",
+                       topoinfo->topo.topo14.max_devs_exceeded);
+               pos += snprintf(buf+pos, PAGE_SIZE,
+                       "max_cascade_exceeded: %d\n",
+                       topoinfo->topo.topo14.max_cascade_exceeded);
+               pos += snprintf(buf+pos, PAGE_SIZE, "device_count: %d\n",
+                       topoinfo->topo.topo14.device_count);
+               pos += snprintf(buf+pos, PAGE_SIZE, "depth: %d\n",
+                       topoinfo->topo.topo14.depth);
+               return pos;
+       }
+
+       return pos;
+}
+
+static ssize_t store_hdcp_topo_info(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct hdmitx_dev *hdev = &hdmitx_device;
+       struct hdcprp_topo *topoinfo = hdev->topo_info;
+       int cnt;
+
+       if (!topoinfo)
+               return count;
+
+       if (hdev->hdcp_mode == 2) {
+               memset(topoinfo, 0, sizeof(struct hdcprp_topo));
+               cnt = sscanf(buf, "%x %x %x %x %x %x",
+                       (int *)&topoinfo->topo.topo22.max_devs_exceeded,
+                       (int *)&topoinfo->topo.topo22.max_cascade_exceeded,
+                       (int *)&topoinfo->topo.topo22.v2_0_repeater_down,
+                       (int *)&topoinfo->topo.topo22.v1_X_device_down,
+                       (int *)&topoinfo->topo.topo22.device_count,
+                       (int *)&topoinfo->topo.topo22.depth);
+               if (cnt < 0)
+                       return count;
+       }
+
+       return count;
+}
+
 static ssize_t show_hdcp22_type(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
@@ -941,10 +1029,17 @@ static ssize_t show_hdcp22_type(struct device *dev,
 static ssize_t store_hdcp22_type(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t count)
 {
-       if (buf[0] == '0')
-               hdmitx_device.hdcp22_type = 0;
+       int type = 0;
+       struct hdmitx_dev *hdev = &hdmitx_device;
+
        if (buf[0] == '1')
-               hdmitx_device.hdcp22_type = 1;
+               type = 1;
+       else
+               type = 0;
+       hdev->hdcp22_type = type;
+
+       pr_info("hdmitx: set hdcp22 content type %d\n", type);
+       hdev->HWOp.CntlDDC(hdev, DDC_HDCP_SET_TOPO_INFO, type);
 
        return count;
 }
@@ -2658,6 +2753,8 @@ 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_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(hdcp22_base, 0444, show_hdcp22_base, NULL);
 static DEVICE_ATTR(div40, 0664, show_div40, store_div40);
@@ -3068,6 +3165,7 @@ static void hdmitx_hpd_plugout_handler(struct work_struct *work)
        hdev->HWOp.CntlConfig(hdev, CONF_CLR_AVI_PACKET, 0);
        hdev->HWOp.CntlDDC(hdev, DDC_HDCP_MUX_INIT, 1);
        hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP, HDCP14_OFF);
+       hdev->HWOp.CntlDDC(hdev, DDC_HDCP_SET_TOPO_INFO, 0);
        hdev->HWOp.CntlMisc(hdev, MISC_TMDS_PHY_OP, TMDS_PHY_DISABLE);
        hdev->hdmitx_event &= ~HDMI_TX_HPD_PLUGOUT;
        hdev->HWOp.CntlMisc(hdev, MISC_ESM_RESET, 0);
@@ -3467,6 +3565,10 @@ static int amhdmitx_device_init(struct hdmitx_dev *hdmi_dev)
        hdmitx_device.audio_param_update_flag = 0;
        /* 1: 2ch */
        hdmitx_device.hdmi_ch = 1;
+       hdmitx_device.topo_info =
+               kmalloc(sizeof(struct hdcprp_topo), GFP_KERNEL);
+       if (!hdmitx_device.topo_info)
+               pr_info("failed to alloc hdcp topo info\n");
        hdmitx_init_parameters(&hdmitx_device.hdmi_info);
 
        return 0;
@@ -3717,6 +3819,7 @@ static int amhdmitx_probe(struct platform_device *pdev)
        ret = device_create_file(dev, &dev_attr_hdcp_byp);
        ret = device_create_file(dev, &dev_attr_hdcp_mode);
        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_hdcp22_base);
        ret = device_create_file(dev, &dev_attr_hdcp_lstore);
@@ -3809,6 +3912,7 @@ static int amhdmitx_remove(struct platform_device *pdev)
        device_remove_file(dev, &dev_attr_hdcp_pwr);
        device_remove_file(dev, &dev_attr_div40);
        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_hdcp22_base);
 
index 8cb746b..d3d521a 100644 (file)
@@ -168,6 +168,7 @@ int hdmitx_ddc_hw_op(enum ddc_op cmd)
 }
 EXPORT_SYMBOL(hdmitx_ddc_hw_op);
 
+static int hdcp_topo_st = -1;
 int hdmitx_hdcp_opr(unsigned int val)
 {
        struct arm_smccc_res res;
@@ -210,6 +211,13 @@ int hdmitx_hdcp_opr(unsigned int val)
                arm_smccc_smc(0x8200001c, 0, 0, 0, 0, 0, 0, 0, &res);
                return (unsigned int)((res.a0)&0xffffffff);
        }
+       if (val == 0xd) { /* HDCP22_SET_TOPO */
+               arm_smccc_smc(0x82000083, hdcp_topo_st, 0, 0, 0, 0, 0, 0, &res);
+       }
+       if (val == 0xe) { /* HDCP22_GET_TOPO */
+               arm_smccc_smc(0x82000084, 0, 0, 0, 0, 0, 0, 0, &res);
+               return (unsigned int)((res.a0)&0xffffffff);
+       }
        return -1;
 }
 
@@ -2864,6 +2872,9 @@ static void hdmitx_debug(struct hdmitx_dev *hdev, const char *buf)
                        pr_info(HW "set hdmi vic count = %d\n",
                                hdev->vic_count);
                }
+       } else if (strncmp(tmpbuf, "topo", 4) == 0) {
+               pr_info("topo: %d\n", hdmitx_hdcp_opr(0xe));
+               return;
        } else if (strncmp(tmpbuf, "dumphdmireg", 11) == 0) {
                unsigned char reg_val = 0;
                unsigned int reg_adr = 0;
@@ -3361,6 +3372,8 @@ static int hdmitx_cntl_ddc(struct hdmitx_dev *hdev, unsigned int cmd,
 {
        int i = 0;
        unsigned char *tmp_char = NULL;
+       struct hdcprp14_topo *topo14 = NULL;
+       unsigned int val;
 
        if ((cmd & CMD_DDC_OFFSET) != CMD_DDC_OFFSET) {
                pr_err(HW "ddc: invalid cmd 0x%x\n", cmd);
@@ -3454,6 +3467,27 @@ static int hdmitx_cntl_ddc(struct hdmitx_dev *hdev, unsigned int cmd,
                return hdmitx_hdcp_opr(0xa);
        case DDC_HDCP_22_LSTORE:
                return hdmitx_hdcp_opr(0xb);
+       case DDC_HDCP14_GET_TOPO_INFO:
+               topo14 = (struct hdcprp14_topo *)argv;
+               /* if rx is not repeater, directly return */
+               if (!(hdmitx_rd_reg(HDMITX_DWC_A_HDCPOBS3) & (1 << 6)))
+                       return 0;
+               hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 1, 0, 1);
+               hdmitx_poll_reg(HDMITX_DWC_A_KSVMEMCTRL, (1<<1), 2 * HZ);
+               val = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_0);
+               topo14->device_count = val & 0x7f;
+               topo14->max_devs_exceeded = !!(val & 0x80);
+               val = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_1);
+               topo14->depth = val & 0x7;
+               topo14->max_cascade_exceeded = !!(val & 0x8);
+               hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 0, 1);
+               return 1;
+       case DDC_HDCP_SET_TOPO_INFO:
+               if (hdcp_topo_st != argv) {
+                       hdcp_topo_st = argv;
+                       hdmitx_hdcp_opr(0xd);
+               }
+               break;
        case DDC_SCDC_DIV40_SCRAMB:
                if (argv == 1) {
                        scdc_wr_sink(TMDS_CFG, 0x3); /* TMDS 1/40 & Scramble */
index e143e27..b028ec2 100644 (file)
@@ -131,6 +131,42 @@ 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---------------------------------- */
index f9ffffe..fa7c6c2 100644 (file)
@@ -342,6 +342,7 @@ struct hdmitx_dev {
        unsigned int audio_notify_flag;
        unsigned int audio_step;
        unsigned int repeater_tx;
+       struct hdcprp_topo *topo_info;
        /* 0.1% clock shift, 1080p60hz->59.94hz */
        unsigned int frac_rate_policy;
        unsigned int rxsense_policy;
@@ -402,6 +403,8 @@ struct hdmitx_dev {
 #define DDC_HDCP_22_LSTORE     (CMD_DDC_OFFSET + 0x10)
 #define DDC_SCDC_DIV40_SCRAMB  (CMD_DDC_OFFSET + 0x20)
 #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)
 
 /***********************************************************************
  *             CONFIG CONTROL //CntlConfig