mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 04:48:04 +09:00
rk30 hdmi: update hdcp driver which pass CTS.
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
#include "../rk30_hdmi_hw.h"
|
||||
#include "rk30_hdmi_hdcp.h"
|
||||
|
||||
struct hdcp *hdcp = NULL;
|
||||
static struct hdcp *hdcp = NULL;
|
||||
|
||||
static void hdcp_work_queue(struct work_struct *work);
|
||||
|
||||
@@ -17,11 +17,11 @@ static void hdcp_work_queue(struct work_struct *work);
|
||||
* Function: hdcp_submit_work
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static struct delayed_work *hdcp_submit_work(int event, int delay)
|
||||
struct delayed_work *hdcp_submit_work(int event, int delay)
|
||||
{
|
||||
struct hdcp_delayed_work *work;
|
||||
|
||||
DBG("%s event %04x delay %d", __FUNCTION__, event, delay);
|
||||
HDCP_DBG("%s event %04x delay %d", __FUNCTION__, event, delay);
|
||||
|
||||
work = kmalloc(sizeof(struct hdcp_delayed_work), GFP_ATOMIC);
|
||||
|
||||
@@ -48,6 +48,7 @@ static void hdcp_cancel_work(struct delayed_work **work)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
return;
|
||||
if (*work) {
|
||||
ret = cancel_delayed_work(*work);
|
||||
if (ret != 1) {
|
||||
@@ -66,11 +67,12 @@ static void hdcp_cancel_work(struct delayed_work **work)
|
||||
*/
|
||||
static void hdcp_wq_authentication_failure(void)
|
||||
{
|
||||
HDCP_DBG("%s hdcp->retry_cnt %d \n", __FUNCTION__, hdcp->retry_cnt);
|
||||
if (hdcp->hdmi_state == HDMI_STOPPED) {
|
||||
return;
|
||||
}
|
||||
|
||||
rk30_hdcp_disable();
|
||||
rk30_hdcp_disable(hdcp);
|
||||
rk30_hdmi_control_output(false);
|
||||
|
||||
hdcp_cancel_work(&hdcp->pending_wq_event);
|
||||
@@ -107,56 +109,119 @@ static void hdcp_wq_start_authentication(void)
|
||||
|
||||
hdcp->hdcp_state = HDCP_AUTHENTICATION_START;
|
||||
|
||||
DBG("HDCP: authentication start");
|
||||
HDCP_DBG("HDCP: authentication start");
|
||||
|
||||
status = rk30_hdcp_start_authentication();
|
||||
status = rk30_hdcp_start_authentication(hdcp);
|
||||
|
||||
if (status != HDCP_OK) {
|
||||
DBG("HDCP: authentication failed");
|
||||
HDCP_DBG("HDCP: authentication failed");
|
||||
hdcp_wq_authentication_failure();
|
||||
} else {
|
||||
hdcp->hdcp_state = HDCP_WAIT_KSV_LIST;
|
||||
hdcp->hdcp_state = HDCP_AUTHENTICATION_1ST;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Function: hdcp_wq_authentication_1st
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static int hdcp_wq_authentication_1st(void)
|
||||
{
|
||||
int status = HDCP_OK;
|
||||
|
||||
HDCP_DBG("1st authen start");
|
||||
|
||||
status = rk30_hdcp_authentication_1st(hdcp);
|
||||
|
||||
if (status == -HDCP_DDC_ERROR)
|
||||
hdcp->pending_wq_event = hdcp_submit_work(HDCP_AUTH_START_1ST, 1000);
|
||||
else if (status != HDCP_OK) {
|
||||
printk(KERN_INFO "HDCP: 1st authen failed %d", status);
|
||||
// hdcp->retry_cnt = 0;
|
||||
hdcp_wq_authentication_failure();
|
||||
}
|
||||
else {
|
||||
HDCP_DBG("HDCP: 1st Authentication successful");
|
||||
hdcp->hdcp_state = HDCP_WAIT_R0_DELAY;
|
||||
// hdcp.auth_state = HDCP_STATE_AUTH_1ST_STEP;
|
||||
}
|
||||
return HDCP_OK;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Function: hdcp_wq_check_r0
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static void hdcp_wq_check_r0(void)
|
||||
{
|
||||
int status = rk30_hdcp_lib_step1_r0_check(hdcp);
|
||||
|
||||
if (status == -HDCP_CANCELLED_AUTH) {
|
||||
HDCP_DBG("Authentication step 1/R0 cancelled.");
|
||||
return;
|
||||
} else if (status < 0)
|
||||
hdcp_wq_authentication_failure();
|
||||
else {
|
||||
if (hdcp_lib_check_repeater_bit_in_tx(hdcp)) {
|
||||
/* Repeater */
|
||||
printk(KERN_INFO "HDCP: authentication step 1 "
|
||||
"successful - Repeater\n");
|
||||
|
||||
hdcp->hdcp_state = HDCP_WAIT_KSV_LIST;
|
||||
// hdcp.auth_state = HDCP_STATE_AUTH_2ND_STEP;
|
||||
|
||||
hdcp->pending_wq_event =
|
||||
hdcp_submit_work(HDCP_AUTH_START_2ND, 0);
|
||||
|
||||
} else {
|
||||
/* Receiver */
|
||||
printk(KERN_INFO "HDCP: authentication step 1 "
|
||||
"successful - Receiver\n");
|
||||
|
||||
hdcp->hdcp_state = HDCP_LINK_INTEGRITY_CHECK;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Function: hdcp_wq_check_bksv
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static void hdcp_wq_check_bksv(void)
|
||||
static void hdcp_wq_step2_authentication(void)
|
||||
{
|
||||
int status = HDCP_OK;
|
||||
|
||||
DBG("Check BKSV start");
|
||||
HDCP_DBG("%s", __FUNCTION__);
|
||||
|
||||
status = rk30_hdcp_check_bksv();
|
||||
status = rk30_hdcp_authentication_2nd(hdcp);
|
||||
|
||||
if (status != HDCP_OK) {
|
||||
printk(KERN_INFO "HDCP: Check BKSV failed");
|
||||
hdcp->retry_cnt = 0;
|
||||
if (status == -HDCP_CANCELLED_AUTH) {
|
||||
HDCP_DBG("Authentication step 2nd cancelled.");
|
||||
return;
|
||||
}
|
||||
else if (status < 0) {
|
||||
printk(KERN_INFO "HDCP: step2 authentication failed");
|
||||
hdcp_wq_authentication_failure();
|
||||
}
|
||||
else {
|
||||
DBG("HDCP: Check BKSV successful");
|
||||
HDCP_DBG("HDCP: step2 authentication successful");
|
||||
|
||||
hdcp->hdcp_state = HDCP_LINK_INTEGRITY_CHECK;
|
||||
|
||||
/* Restore retry counter */
|
||||
if(hdcp->retry_times == 0)
|
||||
hdcp->retry_cnt = HDCP_INFINITE_REAUTH;
|
||||
else
|
||||
hdcp->retry_cnt = hdcp->retry_times;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Function: hdcp_wq_authentication_sucess
|
||||
* Function: hdcp_wq_authentication_3rd
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static void hdcp_wq_authentication_sucess(void)
|
||||
static void hdcp_wq_authentication_3rd(void)
|
||||
{
|
||||
printk(KERN_INFO "HDCP: authentication pass");
|
||||
rk30_hdmi_control_output(true);
|
||||
int status = rk30_hdcp_lib_step3_r0_check(hdcp);
|
||||
|
||||
if (status == -HDCP_CANCELLED_AUTH) {
|
||||
HDCP_DBG("Authentication step 3/Ri cancelled.");
|
||||
return;
|
||||
} else if (status < 0)
|
||||
hdcp_wq_authentication_failure();
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
@@ -168,7 +233,7 @@ static void hdcp_wq_disable(int event)
|
||||
printk(KERN_INFO "HDCP: disabled");
|
||||
|
||||
hdcp_cancel_work(&hdcp->pending_wq_event);
|
||||
rk30_hdcp_disable();
|
||||
rk30_hdcp_disable(hdcp);
|
||||
if(event == HDCP_DISABLE_CTL) {
|
||||
hdcp->hdcp_state = HDCP_DISABLED;
|
||||
if(hdcp->hdmi_state == HDMI_STARTED)
|
||||
@@ -190,7 +255,7 @@ static void hdcp_work_queue(struct work_struct *work)
|
||||
|
||||
mutex_lock(&hdcp->lock);
|
||||
|
||||
DBG("hdcp_work_queue() - START - %u hdmi=%d hdcp=%d evt= %x %d",
|
||||
HDCP_DBG("hdcp_work_queue() - START - %u hdmi=%d hdcp=%d evt= %x %d",
|
||||
jiffies_to_msecs(jiffies),
|
||||
hdcp->hdmi_state,
|
||||
hdcp->hdcp_state,
|
||||
@@ -212,6 +277,10 @@ static void hdcp_work_queue(struct work_struct *work)
|
||||
if (event == HDCP_START_FRAME_EVENT) {
|
||||
hdcp->pending_start = 0;
|
||||
hdcp->hdmi_state = HDMI_STARTED;
|
||||
if(hdcp->retry_times == 0)
|
||||
hdcp->retry_cnt = HDCP_INFINITE_REAUTH;
|
||||
else
|
||||
hdcp->retry_cnt = hdcp->retry_times;
|
||||
}
|
||||
|
||||
/**********************/
|
||||
@@ -246,6 +315,16 @@ static void hdcp_work_queue(struct work_struct *work)
|
||||
|
||||
break;
|
||||
|
||||
case HDCP_AUTHENTICATION_1ST:
|
||||
if(event == HDCP_AUTH_START_1ST)
|
||||
hdcp_wq_authentication_1st();
|
||||
break;
|
||||
|
||||
case HDCP_WAIT_R0_DELAY:
|
||||
if(event == HDCP_R0_EXP_EVENT)
|
||||
hdcp_wq_check_r0();
|
||||
break;
|
||||
|
||||
case HDCP_WAIT_KSV_LIST:
|
||||
/* KSV failure */
|
||||
if (event == HDCP_FAIL_EVENT) {
|
||||
@@ -254,8 +333,8 @@ static void hdcp_work_queue(struct work_struct *work)
|
||||
hdcp_wq_authentication_failure();
|
||||
}
|
||||
/* KSV list ready event */
|
||||
else if (event == HDCP_KSV_LIST_RDY_EVENT)
|
||||
hdcp_wq_check_bksv();
|
||||
else if (event == HDCP_AUTH_START_2ND)
|
||||
hdcp_wq_step2_authentication();
|
||||
break;
|
||||
|
||||
case HDCP_LINK_INTEGRITY_CHECK:
|
||||
@@ -264,8 +343,8 @@ static void hdcp_work_queue(struct work_struct *work)
|
||||
printk(KERN_INFO "HDCP: Ri check failure\n");
|
||||
hdcp_wq_authentication_failure();
|
||||
}
|
||||
else if(event == HDCP_AUTH_PASS_EVENT)
|
||||
hdcp_wq_authentication_sucess();
|
||||
else if(event == HDCP_RI_EXP_EVENT)
|
||||
hdcp_wq_authentication_3rd();
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -286,14 +365,14 @@ static void hdcp_work_queue(struct work_struct *work)
|
||||
*/
|
||||
static void hdcp_start_frame_cb(void)
|
||||
{
|
||||
DBG("hdcp_start_frame_cb()");
|
||||
HDCP_DBG("hdcp_start_frame_cb()");
|
||||
|
||||
/* Cancel any pending work */
|
||||
if (hdcp->pending_start)
|
||||
hdcp_cancel_work(&hdcp->pending_start);
|
||||
if (hdcp->pending_wq_event)
|
||||
hdcp_cancel_work(&hdcp->pending_wq_event);
|
||||
|
||||
hdcp->pending_disable = 0;
|
||||
hdcp->pending_start = hdcp_submit_work(HDCP_START_FRAME_EVENT,
|
||||
HDCP_ENABLE_DELAY);
|
||||
}
|
||||
@@ -304,24 +383,7 @@ static void hdcp_start_frame_cb(void)
|
||||
*/
|
||||
static void hdcp_irq_cb(int interrupt)
|
||||
{
|
||||
int value;
|
||||
DBG("%s 0x%x", __FUNCTION__, interrupt);
|
||||
if(interrupt & m_INT_HDCP_ERR)
|
||||
{
|
||||
value = HDMIRdReg(HDCP_ERROR);
|
||||
HDMIWrReg(HDCP_ERROR, value);
|
||||
printk(KERN_INFO "HDCP: Error 0x%02x\n", value);
|
||||
|
||||
if( (hdcp->hdcp_state != HDCP_DISABLED) &&
|
||||
(hdcp->hdcp_state != HDCP_ENABLE_PENDING) )
|
||||
{
|
||||
hdcp_submit_work(HDCP_FAIL_EVENT, 0);
|
||||
}
|
||||
}
|
||||
else if(interrupt & (m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY))
|
||||
hdcp_submit_work(HDCP_KSV_LIST_RDY_EVENT, 0);
|
||||
else if(interrupt & m_INT_AUTH_DONE)
|
||||
hdcp_submit_work(HDCP_AUTH_PASS_EVENT, 0);
|
||||
rk30_hdcp_irq(hdcp);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
@@ -330,8 +392,8 @@ static void hdcp_irq_cb(int interrupt)
|
||||
*/
|
||||
static int hdcp_power_on_cb(void)
|
||||
{
|
||||
DBG("%s", __FUNCTION__);
|
||||
return rk30_hdcp_load_key2mem(hdcp->keys);
|
||||
HDCP_DBG("%s", __FUNCTION__);
|
||||
return rk30_hdcp_load_key2mem(hdcp, hdcp->keys);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
@@ -340,12 +402,13 @@ static int hdcp_power_on_cb(void)
|
||||
*/
|
||||
static void hdcp_power_off_cb(void)
|
||||
{
|
||||
DBG("%s", __FUNCTION__);
|
||||
HDCP_DBG("%s", __FUNCTION__);
|
||||
if(!hdcp->enable)
|
||||
return;
|
||||
|
||||
hdcp_cancel_work(&hdcp->pending_start);
|
||||
hdcp_cancel_work(&hdcp->pending_wq_event);
|
||||
hdcp->pending_disable = 1;
|
||||
init_completion(&hdcp->complete);
|
||||
/* Post event to workqueue */
|
||||
if (hdcp_submit_work(HDCP_STOP_FRAME_EVENT, 0))
|
||||
@@ -374,11 +437,11 @@ static void hdcp_load_keys_cb(const struct firmware *fw, void *context)
|
||||
|
||||
memcpy(hdcp->keys, fw->data, HDCP_KEY_SIZE);
|
||||
|
||||
rk30_hdcp_load_key2mem(hdcp->keys);
|
||||
rk30_hdcp_load_key2mem(hdcp, hdcp->keys);
|
||||
printk(KERN_INFO "HDCP: loaded hdcp key success\n");
|
||||
|
||||
if(fw->size > HDCP_KEY_SIZE) {
|
||||
DBG("%s invalid key size %d", __FUNCTION__, fw->size - HDCP_KEY_SIZE);
|
||||
HDCP_DBG("%s invalid key size %d", __FUNCTION__, fw->size - HDCP_KEY_SIZE);
|
||||
if((fw->size - HDCP_KEY_SIZE) % 5) {
|
||||
pr_err("HDCP: failed to load invalid keys\n");
|
||||
return;
|
||||
@@ -472,7 +535,7 @@ static int __init rk30_hdcp_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DBG("[%s] %u", __FUNCTION__, jiffies_to_msecs(jiffies));
|
||||
HDCP_DBG("[%s] %u", __FUNCTION__, jiffies_to_msecs(jiffies));
|
||||
|
||||
hdcp = kmalloc(sizeof(struct hdcp), GFP_KERNEL);
|
||||
if(!hdcp)
|
||||
@@ -523,12 +586,12 @@ static int __init rk30_hdcp_init(void)
|
||||
goto error5;
|
||||
}
|
||||
|
||||
rk30_hdmi_register_hdcp_callbacks( hdcp_start_frame_cb,
|
||||
hdcp->hdmi = rk30_hdmi_register_hdcp_callbacks( hdcp_start_frame_cb,
|
||||
hdcp_irq_cb,
|
||||
hdcp_power_on_cb,
|
||||
hdcp_power_off_cb);
|
||||
|
||||
DBG("%s success %u", __FUNCTION__, jiffies_to_msecs(jiffies));
|
||||
HDCP_DBG("%s success %u", __FUNCTION__, jiffies_to_msecs(jiffies));
|
||||
return 0;
|
||||
|
||||
error5:
|
||||
@@ -566,5 +629,6 @@ static void __exit rk30_hdcp_exit(void)
|
||||
}
|
||||
}
|
||||
|
||||
module_init(rk30_hdcp_init);
|
||||
//module_init(rk30_hdcp_init);
|
||||
device_initcall_sync(rk30_hdcp_init);
|
||||
module_exit(rk30_hdcp_exit);
|
||||
@@ -1,10 +1,38 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/io.h>
|
||||
#include <mach/io.h>
|
||||
#include "../rk30_hdmi.h"
|
||||
#include "../rk30_hdmi_hw.h"
|
||||
#include "rk30_hdmi_hdcp.h"
|
||||
|
||||
static int an_ready = 0, sha_ready = 0, i2c_ack = 9;
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Function: hdcp_lib_check_ksv
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static int hdcp_lib_check_ksv(uint8_t ksv[5])
|
||||
{
|
||||
int i, j;
|
||||
int zero = 0, one = 0;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
/* Count number of zero / one */
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (ksv[i] & (0x01 << j))
|
||||
one++;
|
||||
else
|
||||
zero++;
|
||||
}
|
||||
}
|
||||
|
||||
if (one == zero)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void rk30_hdcp_write_mem(int addr_8, char value)
|
||||
{
|
||||
int temp;
|
||||
@@ -18,7 +46,7 @@ static void rk30_hdcp_write_mem(int addr_8, char value)
|
||||
HDMIWrReg(addr_32, temp);
|
||||
}
|
||||
|
||||
int rk30_hdcp_load_key2mem(struct hdcp_keys *key)
|
||||
int rk30_hdcp_load_key2mem(struct hdcp *hdcp, struct hdcp_keys *key)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -39,20 +67,25 @@ int rk30_hdcp_load_key2mem(struct hdcp_keys *key)
|
||||
return HDCP_OK;
|
||||
}
|
||||
|
||||
void rk30_hdcp_disable(void)
|
||||
void rk30_hdcp_disable(struct hdcp *hdcp)
|
||||
{
|
||||
int temp;
|
||||
|
||||
// Diable Encrypt
|
||||
HDMIMskReg(temp, HDCP_CTRL, m_HDCP_FRAMED_ENCRYPED, v_HDCP_FRAMED_ENCRYPED(0));
|
||||
|
||||
// Diable HDCP Interrupt
|
||||
HDMIWrReg(INTR_MASK2, 0x00);
|
||||
HDMIWrReg(SOFT_HDCP_INT_MASK1, 0x00);
|
||||
HDMIWrReg(SOFT_HDCP_INT_MASK2, 0x00);
|
||||
|
||||
// Stop and Reset HDCP
|
||||
HDMIMskReg(temp, HDCP_CTRL, m_HDCP_FRAMED_ENCRYPED | m_HDCP_AUTH_STOP | m_HDCP_RESET,
|
||||
v_HDCP_FRAMED_ENCRYPED(0) | v_HDCP_AUTH_STOP(1) | v_HDCP_RESET(1) );
|
||||
HDMIWrReg(SOFT_HDCP_CTRL1, 0x00);
|
||||
}
|
||||
|
||||
static int rk30_hdcp_load_key(void)
|
||||
static int rk30_hdcp_load_key(struct hdcp *hdcp)
|
||||
{
|
||||
int value, temp = 0;
|
||||
|
||||
|
||||
if(hdcp->keys == NULL) {
|
||||
pr_err("[%s] HDCP key not loaded.\n", __FUNCTION__);
|
||||
return HDCP_KEY_ERR;
|
||||
@@ -75,83 +108,526 @@ static int rk30_hdcp_load_key(void)
|
||||
return HDCP_OK;
|
||||
}
|
||||
|
||||
static int rk30_hdcp_ddc_read(struct hdcp *hdcp, u16 no_bytes, u8 addr, u8 *pdata)
|
||||
{
|
||||
int i, temp;
|
||||
|
||||
i2c_ack = 0;
|
||||
HDMIMskReg(temp, SOFT_HDCP_INT_MASK2, m_I2C_ACK|m_I2C_NO_ACK, 0xC0);
|
||||
HDMIWrReg(HDCP_DDC_ACCESS_LENGTH, no_bytes);
|
||||
HDMIWrReg(HDCP_DDC_OFFSET_ADDR, addr);
|
||||
HDMIWrReg(HDCP_DDC_CTRL, m_DDC_READ);
|
||||
|
||||
while(1) {
|
||||
if(i2c_ack & 0xc0) {
|
||||
break;
|
||||
}
|
||||
msleep(100);
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
}
|
||||
|
||||
HDMIMskReg(temp, SOFT_HDCP_INT_MASK2, m_I2C_ACK|m_I2C_NO_ACK, 0x00);
|
||||
if(i2c_ack & m_I2C_NO_ACK)
|
||||
return -HDCP_DDC_ERROR;
|
||||
|
||||
if(i2c_ack & m_I2C_ACK) {
|
||||
for(i = 0; i < no_bytes; i++)
|
||||
pdata[i] = HDMIRdReg(HDCP_DDC_READ_BUFF + i * 4);
|
||||
}
|
||||
|
||||
return HDCP_OK;
|
||||
}
|
||||
|
||||
int rk30_hdcp_start_authentication(void)
|
||||
static int rk30_hdcp_ddc_write(struct hdcp *hdcp, u16 no_bytes, u8 addr, u8 *pdata)
|
||||
{
|
||||
int i, temp;
|
||||
|
||||
for(i = 0; i < no_bytes; i++)
|
||||
HDMIWrReg(HDCP_DDC_WRITE_BUFF + i * 4, pdata[i]);
|
||||
|
||||
i2c_ack = 0;
|
||||
HDMIMskReg(temp, SOFT_HDCP_INT_MASK2, m_I2C_ACK|m_I2C_NO_ACK, 0xC0);
|
||||
HDMIWrReg(HDCP_DDC_ACCESS_LENGTH, no_bytes);
|
||||
HDMIWrReg(HDCP_DDC_OFFSET_ADDR, addr);
|
||||
HDMIWrReg(HDCP_DDC_CTRL, m_DDC_WRITE);
|
||||
|
||||
while(1) {
|
||||
if(i2c_ack & 0xc0) {
|
||||
break;
|
||||
}
|
||||
msleep(100);
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
}
|
||||
HDMIMskReg(temp, SOFT_HDCP_INT_MASK2, m_I2C_ACK|m_I2C_NO_ACK, 0x00);
|
||||
if(i2c_ack & m_I2C_NO_ACK)
|
||||
return -HDCP_DDC_ERROR;
|
||||
|
||||
return HDCP_OK;
|
||||
}
|
||||
|
||||
int rk30_hdcp_start_authentication(struct hdcp *hdcp)
|
||||
{
|
||||
int rc, temp;
|
||||
|
||||
rc = rk30_hdcp_load_key();
|
||||
struct hdmi* hdmi = hdcp->hdmi;
|
||||
|
||||
rc = rk30_hdcp_load_key(hdcp);
|
||||
if(rc != HDCP_OK)
|
||||
return rc;
|
||||
|
||||
// Set 100ms & 5 sec timer
|
||||
switch(hdmi->vic)
|
||||
{
|
||||
case HDMI_720x576p_50Hz_4_3:
|
||||
case HDMI_720x576p_50Hz_16_9:
|
||||
case HDMI_1280x720p_50Hz:
|
||||
case HDMI_1920x1080i_50Hz:
|
||||
case HDMI_720x576i_50Hz_4_3:
|
||||
case HDMI_720x576i_50Hz_16_9:
|
||||
case HDMI_1920x1080p_50Hz:
|
||||
HDMIWrReg(HDCP_TIMER_100MS, 5);
|
||||
HDMIWrReg(HDCP_TIMER_5S, 250);
|
||||
break;
|
||||
|
||||
default:
|
||||
HDMIWrReg(HDCP_TIMER_100MS, 0x26);
|
||||
HDMIWrReg(HDCP_TIMER_5S, 0x2c);
|
||||
break;
|
||||
}
|
||||
// Config DDC Clock
|
||||
temp = (hdmi->tmdsclk/HDCP_DDC_CLK)/4;
|
||||
HDMIWrReg(DDC_BUS_FREQ_L, temp & 0xFF);
|
||||
HDMIWrReg(DDC_BUS_FREQ_H, (temp >> 8) & 0xFF);
|
||||
// Enable HDCP Interrupt
|
||||
HDMIWrReg(INTR_MASK2, m_INT_HDCP_ERR | m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY | m_INT_AUTH_DONE | m_INT_AUTH_READY);
|
||||
// Start HDCP
|
||||
HDMIMskReg(temp, HDCP_CTRL, m_HDCP_AUTH_START | m_HDCP_FRAMED_ENCRYPED, v_HDCP_AUTH_START(1) | v_HDCP_FRAMED_ENCRYPED(0));
|
||||
|
||||
// Enable Software HDCP INT
|
||||
HDMIWrReg(INTR_MASK2, 0x00);
|
||||
HDMIWrReg(SOFT_HDCP_INT_MASK1, m_SF_MODE_READY);
|
||||
HDMIWrReg(SOFT_HDCP_INT_MASK2, 0x00);
|
||||
|
||||
// Diable Encrypt
|
||||
HDMIMskReg(temp, HDCP_CTRL, m_HDCP_FRAMED_ENCRYPED, v_HDCP_FRAMED_ENCRYPED(0));
|
||||
|
||||
// Enable Software HDCP
|
||||
HDMIWrReg(SOFT_HDCP_CTRL1, v_SOFT_HDCP_AUTH_EN(1));
|
||||
|
||||
return HDCP_OK;
|
||||
}
|
||||
|
||||
int rk30_hdcp_check_bksv(void)
|
||||
static int rk30_hdcp_generate_an(struct hdcp *hdcp, uint8_t ksv[8])
|
||||
{
|
||||
int i, temp;
|
||||
char bksv[5];
|
||||
char *invalidkey;
|
||||
int temp;
|
||||
|
||||
temp = HDMIRdReg(HDCP_BCAPS);
|
||||
DBG("Receiver capacity is 0x%02x", temp);
|
||||
HDCP_DBG("%s", __FUNCTION__);
|
||||
|
||||
#ifdef DEBUG
|
||||
if(temp & m_HDMI_RECEIVED)
|
||||
DBG("Receiver support HDMI");
|
||||
if(temp & m_REPEATER)
|
||||
DBG("Receiver is a repeater");
|
||||
if(temp & m_DDC_FAST)
|
||||
DBG("Receiver support 400K DDC");
|
||||
if(temp & m_1_1_FEATURE)
|
||||
DBG("Receiver support 1.1 features, such as advanced cipher, EESS.");
|
||||
if(temp & m_FAST_REAUTHENTICATION)
|
||||
DBG("Receiver support fast reauthentication.");
|
||||
#endif
|
||||
|
||||
for(i = 0; i < 5; i++) {
|
||||
bksv[i] = HDMIRdReg(HDCP_KSV_BYTE0 + (4 - i)*4) & 0xFF;
|
||||
an_ready = 0;
|
||||
HDMIMskReg(temp, SOFT_HDCP_INT_MASK1, (1 << 4), (1 << 4));
|
||||
HDMIWrReg(SOFT_HDCP_CTRL1, v_SOFT_HDCP_AUTH_EN(1) | v_SOFT_HDCP_PREP_AN(1));
|
||||
|
||||
while(1) {
|
||||
if(an_ready)
|
||||
break;
|
||||
msleep(100);
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
}
|
||||
|
||||
DBG("bksv is 0x%02x%02x%02x%02x%02x", bksv[0], bksv[1], bksv[2], bksv[3], bksv[4]);
|
||||
|
||||
for(i = 0; i < hdcp->invalidkey; i++)
|
||||
{
|
||||
invalidkey = hdcp->invalidkeys + i *5;
|
||||
if(memcmp(bksv, invalidkey, 5) == 0) {
|
||||
printk(KERN_ERR "HDCP: BKSV was revocated!!!\n");
|
||||
HDMIMskReg(temp, HDCP_CTRL, m_HDCP_BKSV_FAILED | m_HDCP_FRAMED_ENCRYPED, v_HDCP_BKSV_FAILED(1) | v_HDCP_FRAMED_ENCRYPED(0));
|
||||
return HDCP_KSV_ERR;
|
||||
}
|
||||
}
|
||||
HDMIMskReg(temp, HDCP_CTRL, m_HDCP_BKSV_PASS | m_HDCP_FRAMED_ENCRYPED, v_HDCP_BKSV_PASS(1) | v_HDCP_FRAMED_ENCRYPED(1));
|
||||
HDMIMskReg(temp, SOFT_HDCP_INT_MASK1, (1 << 4), 0);
|
||||
for(temp = 0; temp < 8; temp++)
|
||||
ksv[temp] = HDMIRdReg(HDCP_AN_BUFF + temp * 4);
|
||||
return HDCP_OK;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Function: hdcp_lib_read_aksv
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static void rk30_hdcp_read_aksv(struct hdcp *hdcp, u8 *ksv_data)
|
||||
{
|
||||
u8 i;
|
||||
int temp;
|
||||
|
||||
// Load AKSV to Reg
|
||||
HDMIMskReg(temp, HDCP_KEY_MEM_CTRL, (1 << 4), (1 << 4));
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
ksv_data[i] = HDMIRdReg(HDCP_AKSV_BUFF + i * 4);
|
||||
}
|
||||
}
|
||||
|
||||
int rk30_hdcp_authentication_1st(struct hdcp *hdcp)
|
||||
{
|
||||
/* HDCP authentication steps:
|
||||
* 1) Read Bksv - check validity (is HDMI Rx supporting HDCP ?)
|
||||
* 2) Initializes HDCP (CP reset release)
|
||||
* 3) Read Bcaps - is HDMI Rx a repeater ?
|
||||
* *** First part authentication ***
|
||||
* 4) Read Bksv - check validity (is HDMI Rx supporting HDCP ?)
|
||||
* 5) Generates An
|
||||
* 6) DDC: Writes An, Aksv
|
||||
* 7) DDC: Write Bksv
|
||||
*/
|
||||
uint8_t an_ksv_data[8];
|
||||
uint8_t rx_type;
|
||||
uint8_t trytimes = 5;
|
||||
int temp, status;
|
||||
/* Generate An */
|
||||
status = rk30_hdcp_generate_an(hdcp, an_ksv_data);
|
||||
if(status < 0)
|
||||
return status;
|
||||
HDCP_DBG("AN: %02x %02x %02x %02x %02x %02x %02x %02x", an_ksv_data[0], an_ksv_data[1],
|
||||
an_ksv_data[2], an_ksv_data[3],
|
||||
an_ksv_data[4], an_ksv_data[5],
|
||||
an_ksv_data[6], an_ksv_data[7]);
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
|
||||
/* DDC: Write An */
|
||||
status = rk30_hdcp_ddc_write(hdcp, DDC_AN_LEN, DDC_AN_ADDR , an_ksv_data);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
|
||||
/* Read AKSV from IP: (HDCP AKSV register) */
|
||||
rk30_hdcp_read_aksv(hdcp, an_ksv_data);
|
||||
|
||||
HDCP_DBG("AKSV: %02x %02x %02x %02x %02x", an_ksv_data[0], an_ksv_data[1],
|
||||
an_ksv_data[2], an_ksv_data[3],
|
||||
an_ksv_data[4]);
|
||||
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
|
||||
if (hdcp_lib_check_ksv(an_ksv_data)) {
|
||||
printk(KERN_INFO "HDCP: AKSV error (number of 0 and 1)\n");
|
||||
return -HDCP_AKSV_ERROR;
|
||||
}
|
||||
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
|
||||
/* DDC: Write AKSV */
|
||||
status = rk30_hdcp_ddc_write(hdcp, DDC_AKSV_LEN, DDC_AKSV_ADDR, an_ksv_data);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
|
||||
/* Read BCAPS to determine if HDCP RX is a repeater */
|
||||
status = rk30_hdcp_ddc_read(hdcp, DDC_BCAPS_LEN, DDC_BCAPS_ADDR, &rx_type);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
HDCP_DBG("bcaps is %02x", rx_type);
|
||||
|
||||
HDMIWrReg(SOFT_HDCP_BCAPS, rx_type);
|
||||
|
||||
if(rx_type & m_REPEATER) {
|
||||
HDCP_DBG("Downstream device is a repeater");
|
||||
HDMIMskReg(temp, SOFT_HDCP_CTRL1, m_SOFT_HDCP_REPEATER, v_SOFT_HDCP_REPEATER(1));
|
||||
}
|
||||
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
|
||||
/* DDC: Read BKSV from RX */
|
||||
while(trytimes--) {
|
||||
status = rk30_hdcp_ddc_read(hdcp, DDC_BKSV_LEN, DDC_BKSV_ADDR, an_ksv_data);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
HDCP_DBG("BKSV: %02x %02x %02x %02x %02x", an_ksv_data[0], an_ksv_data[1],
|
||||
an_ksv_data[2], an_ksv_data[3],
|
||||
an_ksv_data[4]);
|
||||
|
||||
if (hdcp_lib_check_ksv(an_ksv_data) == 0)
|
||||
break;
|
||||
else {
|
||||
HDCP_DBG("BKSV error (number of 0 and 1)");
|
||||
}
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
}
|
||||
if(trytimes == 0)
|
||||
return -HDCP_BKSV_ERROR;
|
||||
|
||||
for(trytimes = 0; trytimes < 5; trytimes++)
|
||||
HDMIWrReg(HDCP_BKSV_BUFF + trytimes * 4, an_ksv_data[trytimes]);
|
||||
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
|
||||
HDMIMskReg(temp, SOFT_HDCP_INT_MASK1, (1 << 6), (1 << 6));
|
||||
HDMIMskReg(temp, SOFT_HDCP_CTRL1, m_SOFT_HDCP_GEN_RI, v_SOFT_HDCP_GEN_RI(1));
|
||||
return HDCP_OK;
|
||||
}
|
||||
|
||||
static int rk30_hdcp_r0_check(struct hdcp *hdcp)
|
||||
{
|
||||
u8 ro_rx[2], ro_tx[2];
|
||||
int status;
|
||||
|
||||
HDCP_DBG("%s()", __FUNCTION__);
|
||||
|
||||
HDMIMskReg(status, SOFT_HDCP_INT_MASK1, (1 << 6), 0);
|
||||
|
||||
/* DDC: Read Ri' from RX */
|
||||
status = rk30_hdcp_ddc_read(hdcp, DDC_Ri_LEN, DDC_Ri_ADDR , (u8 *)&ro_rx);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
/* Read Ri in HDCP IP */
|
||||
ro_tx[0] = HDMIRdReg(HDCP_RI_BUFF);
|
||||
|
||||
ro_tx[1] = HDMIRdReg(HDCP_RI_BUFF + 4);
|
||||
|
||||
/* Compare values */
|
||||
HDCP_DBG("ROTX: %x%x RORX:%x%x", ro_tx[0], ro_tx[1], ro_rx[0], ro_rx[1]);
|
||||
|
||||
if ((ro_rx[0] == ro_tx[0]) && (ro_rx[1] == ro_tx[1]))
|
||||
return HDCP_OK;
|
||||
else
|
||||
return -HDCP_AUTH_FAILURE;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Function: hdcp_lib_check_repeater_bit_in_tx
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
u8 hdcp_lib_check_repeater_bit_in_tx(struct hdcp *hdcp)
|
||||
{
|
||||
return (HDMIRdReg(HDCP_BCAPS) & m_REPEATER);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Function: rk30_hdcp_lib_step1_r0_check
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
int rk30_hdcp_lib_step1_r0_check(struct hdcp *hdcp)
|
||||
{
|
||||
int status = HDCP_OK, temp;
|
||||
|
||||
/* HDCP authentication steps:
|
||||
* 1) DDC: Read M0'
|
||||
* 2) Compare M0 and M0'
|
||||
* if Rx is a receiver: switch to authentication step 3
|
||||
* 3) Enable encryption / auto Ri check / disable AV mute
|
||||
* if Rx is a repeater: switch to authentication step 2
|
||||
* 3) Get M0 from HDMI IP and store it for further processing (V)
|
||||
* 4) Enable encryption / auto Ri check / auto BCAPS RDY polling
|
||||
* Disable AV mute
|
||||
*/
|
||||
|
||||
HDCP_DBG("hdcp_lib_step1_r0_check() %u", jiffies_to_msecs(jiffies));
|
||||
|
||||
status = rk30_hdcp_r0_check(hdcp);
|
||||
if(status < 0)
|
||||
return status;
|
||||
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
|
||||
if (hdcp_lib_check_repeater_bit_in_tx(hdcp)) {
|
||||
|
||||
} else {
|
||||
HDMIMskReg(temp, SOFT_HDCP_INT_MASK2, (1 << 4) | (1 << 5), (1 << 4) | (1 << 5));
|
||||
/* Receiver: enable encryption */
|
||||
HDMIMskReg(temp, HDCP_CTRL, m_HDCP_FRAMED_ENCRYPED, v_HDCP_FRAMED_ENCRYPED(1));
|
||||
HDMIMskReg(temp, SOFT_HDCP_CTRL1, m_SOFT_HDCP_AUTH_START, m_SOFT_HDCP_AUTH_START);
|
||||
}
|
||||
|
||||
return HDCP_OK;
|
||||
}
|
||||
|
||||
static int rk30_hdcp_read_ksvlist(struct hdcp *hdcp, int num)
|
||||
{
|
||||
int i, temp;
|
||||
uint8_t an_ksv_data[5];
|
||||
|
||||
i2c_ack = 0;
|
||||
|
||||
HDCP_DBG("%s", __FUNCTION__);
|
||||
|
||||
HDMIMskReg(temp, SOFT_HDCP_INT_MASK2, m_I2C_ACK|m_I2C_NO_ACK, 0xC0);
|
||||
HDMIWrReg(HDCP_DDC_ACCESS_LENGTH, num * 5);
|
||||
HDMIWrReg(HDCP_DDC_OFFSET_ADDR, DDC_KSV_FIFO_ADDR);
|
||||
HDMIWrReg(HDCP_DDC_CTRL, m_DDC_READ | (1 << 2));
|
||||
|
||||
while(1) {
|
||||
if(i2c_ack & 0xc0) {
|
||||
break;
|
||||
}
|
||||
msleep(100);
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
}
|
||||
|
||||
HDMIMskReg(temp, SOFT_HDCP_INT_MASK2, m_I2C_ACK|m_I2C_NO_ACK, 0x00);
|
||||
if(i2c_ack & m_I2C_NO_ACK)
|
||||
return -HDCP_DDC_ERROR;
|
||||
|
||||
if(i2c_ack & m_I2C_ACK) {
|
||||
for(i = 0; i < num * 5; i++) {
|
||||
temp = HDMIRdReg(0x80 * 4);
|
||||
an_ksv_data[i%5] = temp;
|
||||
if((i+1) % 5 == 0) {
|
||||
HDCP_DBG("BKSV: %02x %02x %02x %02x %02x", an_ksv_data[0], an_ksv_data[1],
|
||||
an_ksv_data[2], an_ksv_data[3],
|
||||
an_ksv_data[4]);
|
||||
if (hdcp_lib_check_ksv(an_ksv_data))
|
||||
return -HDCP_AUTH_FAILURE;
|
||||
// for(temp = 0; temp < 5; temp++)
|
||||
// HDMIWrReg(HDCP_BKSV_BUFF + temp * 4, an_ksv_data[temp]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return HDCP_OK;
|
||||
}
|
||||
|
||||
static int rk30_hdcp_check_sha(struct hdcp *hdcp)
|
||||
{
|
||||
int temp, status;
|
||||
uint8_t asha[4], bsha[4], i;
|
||||
|
||||
HDCP_DBG("%s", __FUNCTION__);
|
||||
|
||||
// Calculate SHA1
|
||||
HDMIMskReg(temp, SOFT_HDCP_INT_MASK1, (1 << 3), (1 << 3));
|
||||
HDMIMskReg(temp, SOFT_HDCP_CTRL1, m_SOFT_HDCP_CAL_SHA, v_SOFT_HDCP_CAL_SHA(1));
|
||||
|
||||
while(1) {
|
||||
if(sha_ready)
|
||||
break;
|
||||
msleep(100);
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
}
|
||||
|
||||
HDMIMskReg(temp, SOFT_HDCP_INT_MASK1, (1 << 3), 0);
|
||||
|
||||
for(temp = 0; temp < 5; temp++) {
|
||||
for(i = 0; i < 4; i++) {
|
||||
HDMIWrReg(HDCP_SHA_INDEX, i);
|
||||
asha[i] = HDMIRdReg(HDCP_SHA_BUF + 4 * temp);
|
||||
}
|
||||
HDCP_DBG("ASHA%d %02x %02x %02x %02x\n", temp, asha[0], asha[1], asha[2], asha[3]);
|
||||
|
||||
status = rk30_hdcp_ddc_read(hdcp, DDC_V_LEN, DDC_V_ADDR + temp * 4, bsha);
|
||||
if(status < 0)
|
||||
return status;
|
||||
|
||||
HDCP_DBG("BSHA%d %02x %02x %02x %02x\n", temp, bsha[0], bsha[1], bsha[2], bsha[3]);
|
||||
|
||||
if( (asha[0] != bsha[0]) || (asha[1] != bsha[1]) || (asha[2] != bsha[2]) || (asha[3] != bsha[3]) )
|
||||
return -HDCP_AUTH_FAILURE;
|
||||
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
|
||||
|
||||
}
|
||||
return HDCP_OK;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Function: rk30_hdcp_authentication_2nd
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
int rk30_hdcp_authentication_2nd(struct hdcp *hdcp)
|
||||
{
|
||||
int status = HDCP_OK;
|
||||
struct timeval ts_start, ts;
|
||||
uint32_t delta = 0, num_dev;
|
||||
uint8_t bstatus[2];
|
||||
|
||||
HDCP_DBG("\n%s", __FUNCTION__);
|
||||
|
||||
do_gettimeofday(&ts_start);
|
||||
while(delta <= 5000000) {
|
||||
/* Poll BCAPS */
|
||||
status = rk30_hdcp_ddc_read(hdcp, DDC_BCAPS_LEN, DDC_BCAPS_ADDR, bstatus);
|
||||
if( (status == HDCP_OK) && (bstatus[0] & (1 << 5)) )
|
||||
break;
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
|
||||
do_gettimeofday(&ts);
|
||||
delta = (ts.tv_sec - ts_start.tv_sec) * 1000000 + (ts.tv_usec - ts_start.tv_usec);
|
||||
msleep(100);
|
||||
}
|
||||
if(delta > 5000000) {
|
||||
HDCP_DBG("Poll BKSV list out of time");
|
||||
return -HDCP_BKSVLIST_TIMEOUT;
|
||||
}
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
|
||||
status = rk30_hdcp_ddc_read(hdcp, DDC_BSTATUS_LEN, DDC_BSTATUS_ADDR, bstatus);
|
||||
if(status < 0)
|
||||
return status;
|
||||
|
||||
HDCP_DBG("bstatus %02x %02x\n", bstatus[1], bstatus[0]);
|
||||
|
||||
if( bstatus[0] & (1 << 7) ) {
|
||||
HDCP_DBG("MAX_DEVS_EXCEEDED");
|
||||
return -HDCP_AUTH_FAILURE;
|
||||
}
|
||||
|
||||
if( bstatus[1] & (1 << 3) ) {
|
||||
HDCP_DBG("MAX_CASCADE_EXCEEDED");
|
||||
return -HDCP_AUTH_FAILURE;
|
||||
}
|
||||
|
||||
num_dev = bstatus[0] & 0x7F;
|
||||
if( num_dev > (MAX_DOWNSTREAM_DEVICE_NUM)) {
|
||||
HDCP_DBG("Out of MAX_DOWNSTREAM_DEVICE_NUM");
|
||||
return -HDCP_AUTH_FAILURE;
|
||||
}
|
||||
|
||||
HDMIWrReg(HDCP_BSTATUS_BUFF, bstatus[0]);
|
||||
HDMIWrReg(HDCP_BSTATUS_BUFF + 4, bstatus[1]);
|
||||
|
||||
HDMIWrReg(HDCP_NUM_DEV, num_dev);
|
||||
|
||||
// Read KSV List
|
||||
if(num_dev) {
|
||||
status = rk30_hdcp_read_ksvlist(hdcp, num_dev);
|
||||
if(status < 0)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
|
||||
status = rk30_hdcp_check_sha(hdcp);
|
||||
if(status < 0)
|
||||
return status;
|
||||
|
||||
if (hdcp->pending_disable)
|
||||
return -HDCP_CANCELLED_AUTH;
|
||||
|
||||
HDMIMskReg(status, SOFT_HDCP_INT_MASK2, (1 << 4) | (1 << 5), (1 << 4) | (1 << 5));
|
||||
/* Receiver: enable encryption */
|
||||
HDMIMskReg(status, HDCP_CTRL, m_HDCP_FRAMED_ENCRYPED, v_HDCP_FRAMED_ENCRYPED(1));
|
||||
HDMIMskReg(status, SOFT_HDCP_CTRL1, m_SOFT_HDCP_AUTH_START, m_SOFT_HDCP_AUTH_START);
|
||||
return HDCP_OK;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Function: rk30_hdcp_lib_step3_r0_check
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
int rk30_hdcp_lib_step3_r0_check(struct hdcp *hdcp)
|
||||
{
|
||||
return rk30_hdcp_r0_check(hdcp);
|
||||
}
|
||||
|
||||
void rk30_hdcp_irq(struct hdcp *hdcp)
|
||||
{
|
||||
int soft_int1, soft_int2;
|
||||
|
||||
soft_int1 = HDMIRdReg(INTR_STATUS3);
|
||||
soft_int2 = HDMIRdReg(INTR_STATUS4);
|
||||
HDMIWrReg(INTR_STATUS3, soft_int1);
|
||||
HDMIWrReg(INTR_STATUS4, soft_int2);
|
||||
HDCP_DBG("soft_int1 %x soft_int2 %x\n", soft_int1, soft_int2);
|
||||
if(soft_int1 & m_SF_MODE_READY)
|
||||
hdcp_submit_work(HDCP_AUTH_START_1ST, 0);
|
||||
if(soft_int1 & m_SOFT_HDCP_AN_READY)
|
||||
an_ready = 1;
|
||||
if(soft_int1 & m_SOFT_HDCP_SHA_READY)
|
||||
sha_ready = 1;
|
||||
if(soft_int1 & m_SOFT_HDCP_RI_READY)
|
||||
hdcp->pending_wq_event =
|
||||
hdcp_submit_work(HDCP_R0_EXP_EVENT,
|
||||
HDCP_R0_DELAY);
|
||||
if(soft_int2 & 0xc0)
|
||||
i2c_ack = soft_int2 & 0xc0;
|
||||
if(soft_int2 & m_SOFT_HDCP_RI_SAVED)
|
||||
hdcp->pending_wq_event =
|
||||
hdcp_submit_work(HDCP_RI_EXP_EVENT,
|
||||
0);
|
||||
}
|
||||
@@ -6,13 +6,42 @@
|
||||
/***************************/
|
||||
|
||||
/* Status / error codes */
|
||||
#define HDCP_OK 0
|
||||
#define HDCP_KEY_ERR 1
|
||||
#define HDCP_KSV_ERR 2
|
||||
enum {
|
||||
HDCP_OK,
|
||||
HDCP_KEY_ERR,
|
||||
HDCP_DDC_ERROR,
|
||||
HDCP_AUTH_FAILURE,
|
||||
HDCP_AKSV_ERROR,
|
||||
HDCP_BKSV_ERROR,
|
||||
HDCP_CANCELLED_AUTH,
|
||||
HDCP_BKSVLIST_TIMEOUT,
|
||||
};
|
||||
|
||||
/* Delays */
|
||||
#define HDCP_ENABLE_DELAY 300
|
||||
#define HDCP_REAUTH_DELAY 100
|
||||
#define HDCP_R0_DELAY 120
|
||||
#define HDCP_KSV_TIMEOUT_DELAY 5000
|
||||
/***********************/
|
||||
/* HDCP DDC addresses */
|
||||
/***********************/
|
||||
|
||||
#define DDC_BKSV_ADDR 0x00
|
||||
#define DDC_Ri_ADDR 0x08
|
||||
#define DDC_AKSV_ADDR 0x10
|
||||
#define DDC_AN_ADDR 0x18
|
||||
#define DDC_V_ADDR 0x20
|
||||
#define DDC_BCAPS_ADDR 0x40
|
||||
#define DDC_BSTATUS_ADDR 0x41
|
||||
#define DDC_KSV_FIFO_ADDR 0x43
|
||||
|
||||
#define DDC_BKSV_LEN 5
|
||||
#define DDC_Ri_LEN 2
|
||||
#define DDC_AKSV_LEN 5
|
||||
#define DDC_AN_LEN 8
|
||||
#define DDC_V_LEN 4//20
|
||||
#define DDC_BCAPS_LEN 1
|
||||
#define DDC_BSTATUS_LEN 2
|
||||
|
||||
/* Event source */
|
||||
#define HDCP_SRC_SHIFT 8
|
||||
@@ -26,10 +55,13 @@
|
||||
#define HDCP_DISABLE_CTL (HDCP_IOCTL_SRC | 1)
|
||||
#define HDCP_START_FRAME_EVENT (HDCP_HDMI_SRC | 2)
|
||||
#define HDCP_STOP_FRAME_EVENT (HDCP_HDMI_SRC | 3)
|
||||
#define HDCP_KSV_LIST_RDY_EVENT (HDCP_IRQ_SRC | 4)
|
||||
#define HDCP_FAIL_EVENT (HDCP_IRQ_SRC | 5)
|
||||
#define HDCP_AUTH_PASS_EVENT (HDCP_IRQ_SRC | 6)
|
||||
#define HDCP_AUTH_REATT_EVENT (HDCP_WORKQUEUE_SRC | 7)
|
||||
#define HDCP_FAIL_EVENT (HDCP_IRQ_SRC | 4)
|
||||
#define HDCP_AUTH_PASS_EVENT (HDCP_IRQ_SRC | 5)
|
||||
#define HDCP_AUTH_START_1ST (HDCP_IRQ_SRC | 6)
|
||||
#define HDCP_RI_EXP_EVENT (HDCP_IRQ_SRC | 7)
|
||||
#define HDCP_AUTH_REATT_EVENT (HDCP_WORKQUEUE_SRC | 8)
|
||||
#define HDCP_R0_EXP_EVENT (HDCP_WORKQUEUE_SRC | 9)
|
||||
#define HDCP_AUTH_START_2ND (HDCP_WORKQUEUE_SRC | 10)
|
||||
|
||||
/* Key size */
|
||||
#define HDCP_KEY_SIZE 308
|
||||
@@ -37,10 +69,15 @@
|
||||
/* Authentication retry times */
|
||||
#define HDCP_INFINITE_REAUTH 0x100
|
||||
|
||||
/* Max downstream device number */
|
||||
#define MAX_DOWNSTREAM_DEVICE_NUM 1
|
||||
|
||||
enum hdcp_states {
|
||||
HDCP_DISABLED,
|
||||
HDCP_ENABLE_PENDING,
|
||||
HDCP_AUTHENTICATION_START,
|
||||
HDCP_AUTHENTICATION_1ST,
|
||||
HDCP_WAIT_R0_DELAY,
|
||||
HDCP_WAIT_KSV_LIST,
|
||||
HDCP_LINK_INTEGRITY_CHECK,
|
||||
};
|
||||
@@ -81,19 +118,76 @@ struct hdcp {
|
||||
struct delayed_work *pending_start;
|
||||
struct delayed_work *pending_wq_event;
|
||||
int retry_cnt;
|
||||
int pending_disable;
|
||||
struct hdmi* hdmi;
|
||||
};
|
||||
|
||||
extern struct hdcp *hdcp;
|
||||
#define SOFT_HDCP_INT_MASK1 0x96 * 4
|
||||
#define m_SF_MODE_READY (1 << 7)
|
||||
|
||||
#define SOFT_HDCP_INT_MASK2 0x97 * 4
|
||||
#define m_I2C_ACK (1 << 7)
|
||||
#define m_I2C_NO_ACK (1 << 6)
|
||||
|
||||
#define SOFT_HDCP_INT1 0x98 * 4
|
||||
#define m_SOFT_HDCP_READY (1 << 7)
|
||||
#define m_SOFT_HDCP_RI_READY (1 << 6)
|
||||
#define m_SOFT_HDCP_AN_READY (1 << 4)
|
||||
#define m_SOFT_HDCP_SHA_READY (1 << 3)
|
||||
|
||||
#define SOFT_HDCP_INT2 0x99 * 4
|
||||
#define m_SOFT_HDCP_RI_SAVED (1 << 5)
|
||||
#define m_SOFT_HDCP_PJ_SAVED (1 << 4)
|
||||
|
||||
#define SOFT_HDCP_CTRL1 0x9A * 4
|
||||
#define m_SOFT_HDCP_AUTH_EN (1 << 7) // enable software hdcp
|
||||
#define m_SOFT_HDCP_AUTH_START (1 << 5)
|
||||
#define m_SOFT_HDCP_PREP_AN (1 << 4)
|
||||
#define m_SOFT_HDCP_REPEATER (1 << 2)
|
||||
#define m_SOFT_HDCP_GEN_RI (1 << 1)
|
||||
#define m_SOFT_HDCP_CAL_SHA (1 << 0)
|
||||
#define v_SOFT_HDCP_AUTH_EN(n) (n << 7)
|
||||
#define v_SOFT_HDCP_PREP_AN(n) (n << 4)
|
||||
#define v_SOFT_HDCP_REPEATER(n) (n << 2)
|
||||
#define v_SOFT_HDCP_GEN_RI(n) (n << 1)
|
||||
#define v_SOFT_HDCP_CAL_SHA(n) (n << 0)
|
||||
|
||||
#define HDCP_DDC_ACCESS_LENGTH 0x9E * 4
|
||||
#define HDCP_DDC_OFFSET_ADDR 0xA0 * 4
|
||||
#define HDCP_DDC_CTRL 0xA1 * 4
|
||||
#define m_DDC_READ (1 << 0)
|
||||
#define m_DDC_WRITE (1 << 1)
|
||||
|
||||
#define SOFT_HDCP_BCAPS 0xE0 * 4
|
||||
|
||||
#define HDCP_DDC_READ_BUFF 0xA2 * 4
|
||||
#define HDCP_DDC_WRITE_BUFF 0xA7 * 4
|
||||
#define HDCP_AN_BUFF 0xE8 * 4
|
||||
#define HDCP_AKSV_BUFF 0xBF * 4
|
||||
#define HDCP_BKSV_BUFF 0xE3 * 4
|
||||
#define HDCP_RI_BUFF 0xD9 * 4
|
||||
#define HDCP_BSTATUS_BUFF 0xE1 * 4
|
||||
|
||||
#define HDCP_NUM_DEV 0xDC * 4
|
||||
#define HDCP_SHA_BUF 0xB9 * 4
|
||||
#define HDCP_SHA_INDEX 0xD8 * 4
|
||||
|
||||
#ifdef HDCP_DEBUG
|
||||
#define DBG(format, ...) \
|
||||
#define HDCP_DBG(format, ...) \
|
||||
printk(KERN_INFO "HDCP: " format "\n", ## __VA_ARGS__)
|
||||
#else
|
||||
#define DBG(format, ...)
|
||||
#define HDCP_DBG(format, ...)
|
||||
#endif
|
||||
|
||||
extern void rk30_hdcp_disable(void);
|
||||
extern int rk30_hdcp_start_authentication(void);
|
||||
extern int rk30_hdcp_check_bksv(void);
|
||||
extern int rk30_hdcp_load_key2mem(struct hdcp_keys *key);
|
||||
extern struct delayed_work *hdcp_submit_work(int event, int delay);
|
||||
extern void rk30_hdcp_disable(struct hdcp *hdcp);
|
||||
extern int rk30_hdcp_start_authentication(struct hdcp *hdcp);
|
||||
extern int rk30_hdcp_check_bksv(struct hdcp *hdcp);
|
||||
extern int rk30_hdcp_load_key2mem(struct hdcp *hdcp, struct hdcp_keys *key);
|
||||
extern int rk30_hdcp_authentication_1st(struct hdcp *hdcp);
|
||||
extern int rk30_hdcp_authentication_2nd(struct hdcp *hdcp);
|
||||
extern void rk30_hdcp_irq(struct hdcp *hdcp);
|
||||
extern int rk30_hdcp_lib_step1_r0_check(struct hdcp *hdcp);
|
||||
extern int rk30_hdcp_lib_step3_r0_check(struct hdcp *hdcp);
|
||||
extern u8 hdcp_lib_check_repeater_bit_in_tx(struct hdcp *hdcp);
|
||||
#endif /* __RK30_HDMI_HDCP_H__ */
|
||||
@@ -27,7 +27,8 @@ extern struct rk_lcdc_device_driver * rk_get_lcdc_drv(char *name);
|
||||
extern void hdmi_register_display_sysfs(struct hdmi *hdmi, struct device *parent);
|
||||
extern void hdmi_unregister_display_sysfs(struct hdmi *hdmi);
|
||||
|
||||
int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),
|
||||
struct hdmi* rk30_hdmi_register_hdcp_callbacks(
|
||||
void (*hdcp_cb)(void),
|
||||
void (*hdcp_irq_cb)(int status),
|
||||
int (*hdcp_power_on_cb)(void),
|
||||
void (*hdcp_power_off_cb)(void))
|
||||
@@ -40,7 +41,7 @@ int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),
|
||||
hdmi->hdcp_power_on_cb = hdcp_power_on_cb;
|
||||
hdmi->hdcp_power_off_cb = hdcp_power_off_cb;
|
||||
|
||||
return HDMI_ERROR_SUCESS;
|
||||
return hdmi;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HAS_EARLYSUSPEND
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
#define HDMI_SOURCE_DEFAULT HDMI_SOURCE_LCDC0
|
||||
#endif
|
||||
|
||||
extern int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),
|
||||
extern struct hdmi* rk30_hdmi_register_hdcp_callbacks(
|
||||
void (*hdcp_cb)(void),
|
||||
void (*hdcp_irq_cb)(int status),
|
||||
int (*hdcp_power_on_cb)(void),
|
||||
void (*hdcp_power_off_cb)(void));
|
||||
|
||||
@@ -8,7 +8,7 @@ static char edid_result = 0;
|
||||
|
||||
static inline void delay100us(void)
|
||||
{
|
||||
msleep(1);
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
int rk30_hdmi_initial(void)
|
||||
@@ -635,9 +635,9 @@ irqreturn_t hdmi_irq(int irq, void *priv)
|
||||
interrupt3 = HDMIRdReg(INTR_STATUS3);
|
||||
interrupt4 = HDMIRdReg(INTR_STATUS4);
|
||||
HDMIWrReg(INTR_STATUS1, interrupt1);
|
||||
HDMIWrReg(INTR_STATUS2, interrupt2);
|
||||
HDMIWrReg(INTR_STATUS3, interrupt3);
|
||||
HDMIWrReg(INTR_STATUS4, interrupt4);
|
||||
// HDMIWrReg(INTR_STATUS2, interrupt2);
|
||||
// HDMIWrReg(INTR_STATUS3, interrupt3);
|
||||
// HDMIWrReg(INTR_STATUS4, interrupt4);
|
||||
#if 0
|
||||
hdmi_dbg(hdmi->dev, "[%s] interrupt1 %02x interrupt2 %02x interrupt3 %02x interrupt4 %02x\n",\
|
||||
__FUNCTION__, interrupt1, interrupt2, interrupt3, interrupt4);
|
||||
@@ -654,12 +654,12 @@ irqreturn_t hdmi_irq(int irq, void *priv)
|
||||
edid_result = interrupt1;
|
||||
spin_unlock(&hdmi->irq_lock);
|
||||
}
|
||||
else if(hdmi->state == HDMI_SLEEP) {
|
||||
hdmi_dbg(hdmi->dev, "hdmi return to sleep mode\n");
|
||||
HDMIWrReg(SYS_CTRL, 0x10);
|
||||
hdmi->pwr_mode = PWR_SAVE_MODE_A;
|
||||
}
|
||||
if(interrupt2 && hdmi->hdcp_irq_cb)
|
||||
// else if(hdmi->state == HDMI_SLEEP) {
|
||||
// RK30DBG( "hdmi return to sleep mode\n");
|
||||
// HDMIWrReg(SYS_CTRL, 0x10);
|
||||
// rk30_hdmi->pwr_mode = PWR_SAVE_MODE_A;
|
||||
// }
|
||||
if(hdmi->hdcp_irq_cb)
|
||||
hdmi->hdcp_irq_cb(interrupt2);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
|
||||
Reference in New Issue
Block a user