#include <linux/miscdevice.h>
#include <linux/workqueue.h>
#include <linux/firmware.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
#include "rk3036_hdmi.h"
#include "rk3036_hdcp.h"
static void hdcp_work_queue(struct work_struct *work);
+#define AUTH_TIMEOUT (2*HZ)
+static struct timer_list auth_timer;
+static int timer_state = 0;
+extern int is_1b_03_test(void);
+
/*-----------------------------------------------------------------------------
* Function: hdcp_submit_work
*-----------------------------------------------------------------------------
}
}
+/*-----------------------------------------------------------------------------
+ * Function: auth_timer_func
+ *-----------------------------------------------------------------------------
+ */
+static void auth_timer_func(unsigned long data)
+{
+ printk(KERN_INFO "hdcp auth 2 second timeout\n");
+ if(hdcp->auth_state == 0) {
+ mod_timer(&auth_timer, jiffies + AUTH_TIMEOUT);
+ if ((hdcp->hdcp_state != HDCP_DISABLED) &&
+ (hdcp->hdcp_state != HDCP_ENABLE_PENDING)) {
+ if (is_1b_03_test())
+ return;
+
+ hdcp_submit_work(HDCP_FAIL_EVENT, 0);
+ }
+ }
+}
+
/*-----------------------------------------------------------------------------
* Function: hdcp_wq_authentication_failure
*-----------------------------------------------------------------------------
}
rk3036_hdcp_disable();
+/*
rk3036_hdmi_control_output(false);
+ */
+ rk3036_set_colorbar(1);
hdcp_cancel_work(&hdcp->pending_wq_event);
if (hdcp->retry_cnt && (hdcp->hdmi_state != HDMI_STOPPED)) {
- if (hdcp->retry_cnt < HDCP_INFINITE_REAUTH) {
+ if (hdcp->retry_cnt <= HDCP_INFINITE_REAUTH) {
hdcp->retry_cnt--;
printk(KERN_INFO "HDCP: authentication failed - "
"retrying, attempts=%d\n",
hdcp->hdcp_state = HDCP_AUTHENTICATION_START;
+ if (hdcp->auth_state == 1 && timer_state == 0) {
+ DBG("add auth timer\n");
+ hdcp->auth_state = 0;
+ hdcp->retry_cnt = HDCP_INFINITE_REAUTH;
+ auth_timer.expires = jiffies + AUTH_TIMEOUT;
+ add_timer(&auth_timer);
+ timer_state = 1;
+ }
+
hdcp->pending_wq_event = hdcp_submit_work(HDCP_AUTH_REATT_EVENT,
HDCP_REAUTH_DELAY);
} else {
printk(KERN_INFO "HDCP: authentication failed - "
"HDCP disabled\n");
hdcp->hdcp_state = HDCP_ENABLE_PENDING;
+
+ if (timer_state == 1) {
+ DBG("delete auth timer\n");
+ del_timer_sync(&auth_timer);
+ timer_state = 0;
+ }
}
}
DBG("HDCP: authentication failed");
hdcp_wq_authentication_failure();
} else {
- hdcp->hdcp_state = HDCP_WAIT_KSV_LIST;
-// hdcp->hdcp_state = HDCP_LINK_INTEGRITY_CHECK;
+// hdcp->hdcp_state = HDCP_WAIT_KSV_LIST;
+ hdcp->hdcp_state = HDCP_LINK_INTEGRITY_CHECK;
}
}
-
+#if 0
/*-----------------------------------------------------------------------------
* Function: hdcp_wq_check_bksv
*-----------------------------------------------------------------------------
hdcp->retry_cnt = hdcp->retry_times;
}
}
-
+#endif
/*-----------------------------------------------------------------------------
* Function: hdcp_wq_authentication_sucess
*-----------------------------------------------------------------------------
*/
static void hdcp_wq_authentication_sucess(void)
{
- rk3036_hdmi_control_output(true);
+ hdcp->auth_state = 1;
+ if (timer_state == 1) {
+ DBG("delete auth timer\n");
+ timer_state = 0;
+ del_timer_sync(&auth_timer);
+ }
+/*
+ rk616_hdmi_control_output(true);
+ */
+ rk3036_set_colorbar(0);
printk(KERN_INFO "HDCP: authentication pass");
}
rk3036_hdcp_disable();
if(event == HDCP_DISABLE_CTL) {
hdcp->hdcp_state = HDCP_DISABLED;
- if(hdcp->hdmi_state == HDMI_STARTED)
- rk3036_hdmi_control_output(true);
- }
- else if(event == HDCP_STOP_FRAME_EVENT)
+ if (hdcp->hdmi_state == HDMI_STARTED)
+ rk3036_set_colorbar(0);
+ } else if (event == HDCP_STOP_FRAME_EVENT) {
hdcp->hdcp_state = HDCP_ENABLE_PENDING;
+ }
}
/*-----------------------------------------------------------------------------
case HDCP_DISABLED:
/* HDCP enable control or re-authentication event */
if (event == HDCP_ENABLE_CTL) {
- if(hdcp->retry_times == 0)
+/*
+ if (hdcp->retry_times == 0)
hdcp->retry_cnt = HDCP_INFINITE_REAUTH;
else
hdcp->retry_cnt = hdcp->retry_times;
+*/
+ hdcp->retry_cnt = HDCP_INFINITE_REAUTH;
if (hdcp->hdmi_state == HDMI_STARTED)
hdcp_wq_start_authentication();
else
hdcp_wq_start_authentication();
break;
-
+#if 0
case HDCP_WAIT_KSV_LIST:
/* KSV failure */
if (event == HDCP_FAIL_EVENT) {
else if (event == HDCP_KSV_LIST_RDY_EVENT)
hdcp_wq_check_bksv();
break;
-
+#endif
case HDCP_LINK_INTEGRITY_CHECK:
- /* Ri failure */
+ /* authentication failure */
if (event == HDCP_FAIL_EVENT) {
printk(KERN_INFO "HDCP: Ri check failure\n");
hdcp_wq_authentication_failure();
if (hdcp->pending_wq_event)
hdcp_cancel_work(&hdcp->pending_wq_event);
+ if (timer_state == 0) {
+ DBG("add auth timer\n");
+ auth_timer.expires = jiffies + AUTH_TIMEOUT;
+ add_timer(&auth_timer);
+ timer_state = 1;
+ }
+
+ hdcp->retry_cnt = HDCP_INFINITE_REAUTH;
+
hdcp->pending_start = hdcp_submit_work(HDCP_START_FRAME_EVENT,
HDCP_ENABLE_DELAY);
}
hdcp_submit_work(HDCP_FAIL_EVENT, 0);
}
}
+/*
else if(interrupt1 & (m_INT_BKSV_READY | m_INT_BKSV_UPDATE))
hdcp_submit_work(HDCP_KSV_LIST_RDY_EVENT, 0);
+ */
else if(interrupt1 & m_INT_AUTH_SUCCESS)
hdcp_submit_work(HDCP_AUTH_PASS_EVENT, 0);
}
static int hdcp_power_on_cb(void)
{
DBG("%s", __FUNCTION__);
-// return rk3036_hdcp_load_key2mem(hdcp->keys);
+ return rk3036_hdcp_load_key2mem(hdcp->keys);
return HDCP_OK;
}
static void hdcp_power_off_cb(void)
{
DBG("%s", __FUNCTION__);
+ if (timer_state == 1) {
+ DBG("delete auth timer\n");
+ timer_state = 0;
+ del_timer_sync(&auth_timer);
+ }
+ hdcp->auth_state = 0;
+
if(!hdcp->enable)
return;
-
+ rk3036_hdcp_stop_authentication();
hdcp_cancel_work(&hdcp->pending_start);
hdcp_cancel_work(&hdcp->pending_wq_event);
init_completion(&hdcp->complete);
msecs_to_jiffies(5000));
}
-// Load HDCP key to external HDCP memory
+/*
+ * Load HDCP key to external HDCP memory
+ */
static void hdcp_load_keys_cb(const struct firmware *fw, void *context)
{
if (!fw) {
hdcp_irq_cb,
hdcp_power_on_cb,
hdcp_power_off_cb);
-
+
+ init_timer(&auth_timer);
+ auth_timer.data = 0;
+ auth_timer.function = auth_timer_func;
DBG("%s success %u", __FUNCTION__, jiffies_to_msecs(jiffies));
return 0;
kfree(hdcp);
}
-module_init(rk3036_hdcp_init);
+/* module_init(rk3036_hdcp_init); */
+late_initcall_sync(rk3036_hdcp_init);
module_exit(rk3036_hdcp_exit);
#include "rk3036_hdmi.h"
#include "rk3036_hdmi_hw.h"
#include "rk3036_hdcp.h"
+int is_1b_03_test(void)
+{
+ int reg_value;
+ int reg_val_1;
+ hdmi_readl(hdmi_dev, 0x58, ®_value);
+ hdmi_readl(hdmi_dev, 0xc3, ®_val_1);
-#define HDCPWrReg HDMIWrReg
-#define HDCPRdReg HDMIRdReg
-#define HDCPMskReg(temp,addr,Msk,val) do{ \
- HDMIRdReg(addr,&temp); \
- HDMIWrReg(addr, ((val)&(Msk))|(temp&(~Msk))); \
- }while(0)
-
+ if (reg_value != 0) {
+ if ((reg_val_1 & 0x40) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+void rk3036_set_colorbar(int enable)
+{
+ static int display_mask = 0;
+ int reg_value;
+ if (enable) {
+ if (!display_mask) {
+ if (hdmi_dev->driver.tmdsclk <= (HDMI_SYS_FREG_CLK << 2)) {
+ hdmi_readl(hdmi_dev, SYS_CTRL, ®_value);
+ hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_SYS);
+ hdmi_writel(hdmi_dev, HDMI_COLORBAR, 0x00);
+ hdmi_writel(hdmi_dev, SYS_CTRL, reg_value);
+ } else {
+ hdmi_writel(hdmi_dev, HDMI_COLORBAR, 0x00);
+ }
+
+ display_mask = 1;
+ }
+ } else {
+ if (display_mask) {
+
+ if (hdmi_dev->driver.tmdsclk <= (HDMI_SYS_FREG_CLK << 2)) {
+ hdmi_readl(hdmi_dev, SYS_CTRL, ®_value);
+ hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_SYS);
+ hdmi_writel(hdmi_dev, HDMI_COLORBAR, 0x10);
+ hdmi_writel(hdmi_dev, SYS_CTRL, reg_value);
+ } else {
+ hdmi_writel(hdmi_dev, HDMI_COLORBAR, 0x10);
+ }
+
+ display_mask = 0;
+ }
+ }
+}
void rk3036_hdcp_disable(void)
{
- char temp;
-
+ int reg_value;
+ if (hdmi_dev->driver.tmdsclk <= (HDMI_SYS_FREG_CLK << 2)) {
+ hdmi_readl(hdmi_dev, SYS_CTRL, ®_value);
+ hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_SYS);
+ }
+
// Diable HDCP Interrupt
- HDCPWrReg(HDCP_INT_MASK1, 0x00);
+ hdmi_writel(hdmi_dev, HDCP_INT_MASK1, 0x00);
// Stop and Reset HDCP
- HDCPMskReg(temp, HDCP_CTRL1, m_ENCRYPT_ENABLE | m_AUTH_STOP | m_HDCP_RESET,
- v_ENCRYPT_ENABLE(0) | v_AUTH_STOP(1) | v_HDCP_RESET(1) );
+ hdmi_msk_reg(hdmi_dev, HDCP_CTRL1, m_AUTH_START | m_AUTH_STOP | m_HDCP_RESET,
+ v_AUTH_START(0) | v_AUTH_STOP(1) | v_HDCP_RESET(1) );
+
+ if (hdmi_dev->driver.tmdsclk <= (HDMI_SYS_FREG_CLK << 2))
+ hdmi_writel(hdmi_dev, SYS_CTRL, reg_value);
+
}
-int rk3036_hdcp_load_key2mem(struct hdcp_keys *key)
+int rk3036_hdcp_key_check(struct hdcp_keys *key)
+{
+ int i = 0;
+
+ DBG("HDCP: check hdcp key\n");
+ //check 40 private key
+ for(i = 0; i < HDCP_PRIVATE_KEY_SIZE; i++){
+ if(key->DeviceKey[i] != 0x00)
+ return HDCP_KEY_VALID;
+ }
+ //check aksv
+ for(i = 0; i < 5; i++){
+ if(key->KSV[i] != 0x00)
+ return HDCP_KEY_VALID;
+ }
+
+ return HDCP_KEY_INVALID;
+}
+int rk3036_hdcp_load_key2mem(struct hdcp_keys *key)
{
int i;
DBG("HDCP: rk3036_hdcp_load_key2mem start");
// Write 40 private key
for(i = 0; i < HDCP_PRIVATE_KEY_SIZE; i++)
- HDCPWrReg(HDCP_KEY_FIFO, key->DeviceKey[i]);
+ hdmi_writel(hdmi_dev, HDCP_KEY_FIFO, key->DeviceKey[i]);
// Write 1st aksv
for(i = 0; i < 5; i++)
- HDCPWrReg(HDCP_KEY_FIFO, key->KSV[i]);
+ hdmi_writel(hdmi_dev, HDCP_KEY_FIFO, key->KSV[i]);
// Write 2nd aksv
for(i = 0; i < 5; i++)
- HDCPWrReg(HDCP_KEY_FIFO, key->KSV[i]);
+ hdmi_writel(hdmi_dev, HDCP_KEY_FIFO, key->KSV[i]);
DBG("HDCP: rk3036_hdcp_load_key2mem end");
return HDCP_OK;
}
-int rk3036_hdcp_start_authentication(void)
+int rk3036_hdcp_start_authentication(void)
{
- char temp;
+ int temp;
int retry = 0;
if(hdcp->keys == NULL) {
return HDCP_KEY_ERR;
}
- // Select TMDS CLK to configure regs
- HDCPMskReg(temp, SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_TMDS);
-
- HDCPRdReg(HDCP_KEY_STATUS,&temp);
+ if(rk3036_hdcp_key_check(hdcp->keys) == HDCP_KEY_INVALID){
+ printk(KERN_ERR "loaded HDCP key is incorrect\n");
+ return HDCP_KEY_ERR;
+ }
+
+ if (hdmi_dev->driver.tmdsclk > (HDMI_SYS_FREG_CLK << 2)) {
+ // Select TMDS CLK to configure regs
+ hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_TMDS);
+ } else {
+ hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_SYS);
+ }
+
+ hdmi_writel(hdmi_dev, HDCP_TIMER_100MS,0x28);
+ hdmi_readl(hdmi_dev, HDCP_KEY_STATUS,&temp);
while( ( temp & m_KEY_READY) == 0 ) {
- if(retry > 10) {
+ if(retry > 1000) {
printk(KERN_ERR "HDCP: loaded key error\n");
return HDCP_KEY_ERR;
}
rk3036_hdcp_load_key2mem(hdcp->keys);
msleep(1);
- HDCPRdReg(HDCP_KEY_STATUS,&temp);
+ hdmi_readl(hdmi_dev, HDCP_KEY_STATUS,&temp);
+ retry++;
}
-
+
// Config DDC bus clock: ddc_clk = reg_clk/4*(reg 0x4c 0x4b)
- DBG("TMDS frequency %d", hdmi->tmdsclk);
- retry = hdmi->tmdsclk/(HDCP_DDC_CLK*4);
- HDCPWrReg(DDC_CLK_L, retry & 0xFF);
- HDCPWrReg(DDC_CLK_H, (retry >> 8) & 0xFF);
-
- HDCPWrReg(HDCP_CTRL2, 0x00);
-
+ retry = hdmi_dev->hclk_rate/(HDCP_DDC_CLK << 2);
+ hdmi_writel(hdmi_dev, DDC_CLK_L, retry & 0xFF);
+ hdmi_writel(hdmi_dev, DDC_CLK_H, (retry >> 8) & 0xFF);
+
+ hdmi_writel(hdmi_dev, HDCP_CTRL2, 0x67);
+
//Enable interrupt
- HDCPWrReg(HDCP_INT_MASK1, m_INT_HDCP_ERR | m_INT_BKSV_READY | m_INT_BKSV_UPDATE | m_INT_AUTH_SUCCESS | m_INT_AUTH_READY);
-// HDCPWrReg(HDCP_INT_MASK2, 0xFF);
+ hdmi_writel(hdmi_dev, HDCP_INT_MASK1, m_INT_HDCP_ERR | m_INT_BKSV_READY | m_INT_BKSV_UPDATE | m_INT_AUTH_SUCCESS | m_INT_AUTH_READY);
+ hdmi_writel(hdmi_dev, HDCP_INT_MASK2, 0x00);
+
//Start authentication
- HDCPMskReg(temp, HDCP_CTRL1, m_AUTH_START | m_ENCRYPT_ENABLE | m_ADVANED_ENABLE, v_AUTH_START(1) | v_ENCRYPT_ENABLE(1) | v_ADVANED_ENABLE(0));
-
+ hdmi_msk_reg(hdmi_dev, HDCP_CTRL1, m_AUTH_START | m_ENCRYPT_ENABLE | m_ADVANED_ENABLE | m_AUTH_STOP | m_HDCP_RESET,
+ v_AUTH_START(1) | v_ENCRYPT_ENABLE(1) | v_ADVANED_ENABLE(0) | v_AUTH_STOP(0) | v_HDCP_RESET(0));
+
+ if (hdmi_dev->driver.tmdsclk <= (HDMI_SYS_FREG_CLK << 2)) {
+ hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_TMDS);
+ }
return HDCP_OK;
}
+int rk3036_hdcp_stop_authentication(void)
+{
+ hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_SYS);
+ hdmi_writel(hdmi_dev, DDC_CLK_L, 0x1c);
+ hdmi_writel(hdmi_dev, DDC_CLK_H, 0x00);
+ hdmi_writel(hdmi_dev, HDCP_CTRL2, 0x08);
+ hdmi_writel(hdmi_dev, HDCP_INT_MASK2, 0x06);
+ hdmi_writel(hdmi_dev, HDCP_CTRL1, 0x02);
+ return 0;
+ //hdmi_writel(HDCP_CTRL1, 0x0a);
+}
+#if 0
int rk3036_hdcp_check_bksv(void)
{
int i, j;
char *invalidkey;
for(i = 0; i < 5; i++) {
- HDCPRdReg(HDCP_KSV_BYTE0 + (4 - i),&temp);
+ hdmi_readl(HDCP_KSV_BYTE0 + (4 - i), &temp);
bksv[i] = temp & 0xFF;
}
DBG("bksv is 0x%02x%02x%02x%02x%02x", bksv[0], bksv[1], bksv[2], bksv[3], bksv[4]);
invalidkey = hdcp->invalidkeys + i *5;
if(memcmp(bksv, invalidkey, 5) == 0) {
printk(KERN_ERR "HDCP: BKSV was revocated!!!\n");
- HDCPMskReg(temp, HDCP_CTRL1, m_BKSV_INVALID | m_ENCRYPT_ENABLE, v_BKSV_INVALID(1) | v_ENCRYPT_ENABLE(1));
+ hdmi_msk_reg(HDCP_CTRL1, m_BKSV_INVALID | m_ENCRYPT_ENABLE, v_BKSV_INVALID(1) | v_ENCRYPT_ENABLE(1));
return HDCP_KSV_ERR;
}
}
- HDCPMskReg(temp, HDCP_CTRL1, m_BKSV_VALID | m_ENCRYPT_ENABLE, v_BKSV_VALID(1) | v_ENCRYPT_ENABLE(1));
+ hdmi_msk_reg(HDCP_CTRL1, m_BKSV_VALID | m_ENCRYPT_ENABLE, v_BKSV_VALID(1) | v_ENCRYPT_ENABLE(1));
return HDCP_OK;
}
+#endif
+
+int rk3036_hdcp_error(int value)
+{
+ if (value & 0x80) {
+ printk("Timed out waiting for downstream repeater\n");
+ } else if (value & 0x40) {
+ printk("Too many devices connected to repeater tree\n");
+
+ } else if (value & 0x20) {
+ printk("SHA-1 hash check of BKSV list failed\n");
+
+ } else if (value & 0x10) {
+ printk("SHA-1 hash check of BKSV list failed\n");
+
+ } else if (value & 0x08) {
+ printk("DDC channels no acknowledge\n");
+
+ } else if (value & 0x04) {
+ printk("Pj mismatch\n");
+
+ } else if (value & 0x02) {
+ printk("Ri mismatch\n");
+
+ } else if (value & 0x01) {
+ printk("Bksv is wrong\n");
+
+ } else {
+ return 0;
+ }
+ return 1;
+}
void rk3036_hdcp_interrupt(char *status1, char *status2)
{
- char interrupt1 = 0;
- char interrupt2 = 0;
- char temp =0;
- HDCPRdReg(HDCP_INT_STATUS1,&interrupt1);
- HDCPRdReg(HDCP_INT_STATUS2,&interrupt2);
+ int interrupt1 = 0;
+ int interrupt2 = 0;
+ int temp =0;
+
+ hdmi_readl(hdmi_dev, HDCP_INT_STATUS1,&interrupt1);
+ hdmi_readl(hdmi_dev, HDCP_INT_STATUS2,&interrupt2);
+
+ if (hdmi_dev->driver.tmdsclk <= (HDMI_SYS_FREG_CLK << 2))
+ hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_SYS);
+
if(interrupt1) {
- HDCPWrReg(HDCP_INT_STATUS1, interrupt1);
+ hdmi_writel(hdmi_dev, HDCP_INT_STATUS1, interrupt1);
if(interrupt1 & m_INT_HDCP_ERR){
- HDCPRdReg(HDCP_ERROR,&temp);
- printk(KERN_INFO "HDCP: Error 0x%02x\n", temp);
+ hdmi_readl(hdmi_dev, HDCP_ERROR,&temp);
+ printk(KERN_INFO "HDCP: Error reg 0x65 = 0x%02x\n", temp);
+ rk3036_hdcp_error(temp);
+ hdmi_writel(hdmi_dev, HDCP_ERROR, temp);
}
}
if(interrupt2)
- HDCPWrReg(HDCP_INT_STATUS2, interrupt2);
+ hdmi_writel(hdmi_dev, HDCP_INT_STATUS2, interrupt2);
*status1 = interrupt1;
*status2 = interrupt2;
+
+ if (hdmi_dev->driver.tmdsclk <= (HDMI_SYS_FREG_CLK << 2))
+ hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_TMDS);
+/*
+ hdmi_readl(HDCP_ERROR, &temp);
+ DBG("HDCP: Error reg 0x65 = 0x%02x\n", temp);
+*/
}