diff --git a/MAINTAINERS b/MAINTAINERS index c37a51f4c158..a0085788bd33 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13539,8 +13539,8 @@ F: arch/arm/mach-meson/Makefile.boot HDMITX OUTPUT DRIVER M: Yi Zhou -M: Kaifu Hu M: Zongdong Jiao +M: Kaifu Hu S: Maintained F: drivers/amlogic/media/vout/hdmitx/* F: drivers/amlogic/media/vout/hdmitx/hdcp/* diff --git a/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_edid.c b/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_edid.c index a77e7f85a85c..d24187cfa6d4 100644 --- a/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_edid.c +++ b/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_edid.c @@ -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)); diff --git a/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_hdcp.h b/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_hdcp.h index ae39f444eff9..88c2b6ff42b1 100644 --- a/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_hdcp.h +++ b/drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_hdcp.h @@ -27,7 +27,6 @@ * other devices */ extern int hdcp_ksv_valid(unsigned char *dat); -extern unsigned int hdcp_get_downstream_ver(void); #endif 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 756ce6c3056c..2ed30fb29005 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 @@ -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(); @@ -633,6 +636,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) { @@ -2596,24 +2676,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; } /* @@ -2819,6 +2928,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, @@ -2853,6 +2969,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) { @@ -2931,39 +3094,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); -} -EXPORT_SYMBOL(direct_hdcptx14_start); + int pos = 0; -void direct_hdcptx14_stop(void) -{ - pr_info("%s[%d]", __func__, __LINE__); - hdmitx_device.HWOp.CntlDDC(&hdmitx_device, - DDC_HDCP_OP, HDCP14_OFF); + pos += snprintf(buf+pos, PAGE_SIZE, "%d\n", hdcp_sticky_mode); + + return pos; } -EXPORT_SYMBOL(direct_hdcptx14_stop); + +static ssize_t store_hdcp_stickmode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + 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 + +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_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; - dev_warn(dev, "hdmitx20: %s\n", buf); + + /* 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; + } + /* 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; @@ -3047,6 +3290,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) { @@ -3105,6 +3368,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); @@ -3116,11 +3380,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); @@ -3128,6 +3399,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); @@ -3451,9 +3724,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); @@ -3478,7 +3753,6 @@ static void hdmitx_hpd_plugin_handler(struct work_struct *work) } 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]) @@ -3486,7 +3760,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); @@ -3539,7 +3812,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))) { @@ -4011,6 +4285,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); @@ -4202,6 +4484,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); @@ -4216,11 +4499,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); @@ -4296,6 +4585,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); @@ -4309,7 +4600,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); 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 b3268c6a7d83..f87a34065d64 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 @@ -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); @@ -269,6 +277,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) { @@ -463,6 +496,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 */ @@ -580,6 +615,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); @@ -612,60 +651,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); @@ -676,13 +718,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; } @@ -2628,8 +2667,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); @@ -4403,8 +4448,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; @@ -4453,68 +4496,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 */ @@ -4527,9 +4556,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); @@ -4539,12 +4570,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); @@ -4552,15 +4589,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); @@ -4568,27 +4640,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)) { @@ -4602,30 +4690,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) @@ -4639,10 +4705,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); } @@ -4672,6 +4736,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) { @@ -4731,22 +4809,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 */ @@ -4754,6 +4843,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++) @@ -4962,6 +5054,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; @@ -5002,16 +5096,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; @@ -5087,7 +5189,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); } @@ -5504,7 +5609,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; 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 4bc17773871c..ca037ef68284 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,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 index 000000000000..3b1d9813bcb0 --- /dev/null +++ b/include/linux/amlogic/media/vout/hdmi_tx/hdmi_rptx.h @@ -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 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 366e2049398c..5ef3d54b0b54 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 @@ -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,