From: Zongdong Jiao Date: Thu, 24 May 2018 08:16:11 +0000 (+0800) Subject: hdmitx: add hdcp topo information [3/5] X-Git-Tag: khadas-vims-v0.9.6-release~1997 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=715a75cd6952ed4cde2c87afa22d525a98babe84;p=platform%2Fkernel%2Flinux-amlogic.git hdmitx: add hdcp topo information [3/5] 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 --- diff --git a/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c b/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c index 9e22725..280df7f 100644 --- a/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c +++ b/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c @@ -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); diff --git a/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c b/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c index 8cb746b..d3d521a 100644 --- a/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c +++ b/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/hdmi_tx_hw.c @@ -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 */ diff --git a/include/linux/amlogic/media/vout/hdmi_tx/hdmi_info_global.h b/include/linux/amlogic/media/vout/hdmi_tx/hdmi_info_global.h index e143e27..b028ec2 100644 --- a/include/linux/amlogic/media/vout/hdmi_tx/hdmi_info_global.h +++ b/include/linux/amlogic/media/vout/hdmi_tx/hdmi_info_global.h @@ -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---------------------------------- */ diff --git a/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h b/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h index f9ffffe..fa7c6c2 100644 --- a/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h +++ b/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h @@ -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