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/*
}
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;
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];
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:
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));
* other devices
*/
extern int hdcp_ksv_valid(unsigned char *dat);
-extern unsigned int hdcp_get_downstream_ver(void);
#endif
|| 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);
/* 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);
{
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);
hdev, STAT_VIDEO_VIC, 0);
memset(mode, 0, sizeof(mode));
+ hdev->ready = 0;
/* get current vinfo */
info = hdmitx_get_current_vinfo();
}
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)
{
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;
}
/*
{
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,
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)
{
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;
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)
{
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);
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);
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);
}
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)
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])
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);
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))) {
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);
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);
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);
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);
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);
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);
#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();
}
}
+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)
{
/* 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 */
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);
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);
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;
}
}
}
+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);
}
} /* hdmi20_tx_read_edid */
-#define HDCP_NMOOFDEVICES 127
-
static int get_hdcp_depth(void)
{
int ret;
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 */
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);
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);
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);
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)) {
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)
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);
}
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)
{
}
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 */
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++)
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;
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;
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);
}
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;
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---------------------------------- */
--- /dev/null
+/*
+ * 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
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,
};
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;
};
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 {
struct delayed_work cec_work;
#endif
struct timer_list hdcp_timer;
- int hdcp_try_times;
int chip_type;
int hdmi_init;
int hpdmode;
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 {
/**/
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;
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 */
#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)
#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)
#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
#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
{
}
-/*
- * 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,