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)
{
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;
}
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);
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);
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;
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);
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);
}
EXPORT_SYMBOL(hdmitx_ddc_hw_op);
+static int hdcp_topo_st = -1;
int hdmitx_hdcp_opr(unsigned int val)
{
struct arm_smccc_res res;
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;
}
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;
{
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);
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 */