rk30 hdmi: update hdcp driver which pass CTS.
authorZheng Yang <zhengyang@rock-chips.com>
Fri, 26 Jul 2013 02:03:22 +0000 (10:03 +0800)
committerZheng Yang <zhengyang@rock-chips.com>
Fri, 26 Jul 2013 02:03:22 +0000 (10:03 +0800)
drivers/video/rockchip/hdmi/chips/rk30/hdcp/rk30_hdcp.c
drivers/video/rockchip/hdmi/chips/rk30/hdcp/rk30_hdmi_hdcp.c
drivers/video/rockchip/hdmi/chips/rk30/hdcp/rk30_hdmi_hdcp.h
drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi.c
drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi.h
drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi_hw.c

index 68d0ac841a67dc6b34fd42f95d6cc85eb0afce8b..c0411214854b8c285dd4e48d3d511c2f623efe7f 100755 (executable)
@@ -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);
\ No newline at end of file
index 1184989a57b256481cb00088fabfc79483c3e5cb..294d9cfc3e48ac2d4bed248fdec15e091536d6c7 100755 (executable)
@@ -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;
 }
 
-
-int rk30_hdcp_start_authentication(void)
+static int rk30_hdcp_ddc_read(struct hdcp *hdcp, u16 no_bytes, u8 addr, u8 *pdata)
 {
-       int rc, temp;
+       int i, temp;
        
-       rc = rk30_hdcp_load_key();
-       if(rc != HDCP_OK)
-               return rc;
+       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);
        
-       // 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);
+       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;
                
-               default:
-                       HDMIWrReg(HDCP_TIMER_100MS, 0x26);
-                       HDMIWrReg(HDCP_TIMER_5S, 0x2c);
+       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;
+}
+
+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;
+       struct hdmi* hdmi = hdcp->hdmi;
+
+       rc = rk30_hdcp_load_key(hdcp);
+       if(rc != HDCP_OK)
+               return rc;
+       
        // 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;
+}
+
+static int rk30_hdcp_generate_an(struct hdcp *hdcp, uint8_t ksv[8])
+{
+       int temp;
+       
+       HDCP_DBG("%s", __FUNCTION__);
+       
+       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;
+       }
+       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;
 }
 
-int rk30_hdcp_check_bksv(void)
+static int rk30_hdcp_read_ksvlist(struct hdcp *hdcp, int num)
 {
        int i, temp;
-       char bksv[5];
-       char *invalidkey;
-       
-       temp = HDMIRdReg(HDCP_BCAPS);
-       DBG("Receiver capacity is 0x%02x", temp);
-       
-#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;
-       }
-       
-       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;
+       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]);
+                       }
                }
        }
-       HDMIMskReg(temp, HDCP_CTRL, m_HDCP_BKSV_PASS | m_HDCP_FRAMED_ENCRYPED, v_HDCP_BKSV_PASS(1) | v_HDCP_FRAMED_ENCRYPED(1));
        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);
+}
\ No newline at end of file
index 0224d88ab134003a904f43f6584e65e538cbfedb..d3183e993c8ab778f3f17563176e05fd3d17cf55 100755 (executable)
@@ -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
 #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     
 /* 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__ */
\ No newline at end of file
index 63ddcc622d998960714d4cd8c4c12e047e0fc731..a33f7e65468ec978e893c3e624f31d0b66994413 100755 (executable)
@@ -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);\r
 extern void hdmi_unregister_display_sysfs(struct hdmi *hdmi);\r
 \r
-int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),\r
+struct hdmi* rk30_hdmi_register_hdcp_callbacks( \r
+                                        void (*hdcp_cb)(void),\r
                                         void (*hdcp_irq_cb)(int status),\r
                                         int (*hdcp_power_on_cb)(void),\r
                                         void (*hdcp_power_off_cb)(void))\r
@@ -40,7 +41,7 @@ int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),
        hdmi->hdcp_power_on_cb = hdcp_power_on_cb;\r
        hdmi->hdcp_power_off_cb = hdcp_power_off_cb;\r
        \r
-       return HDMI_ERROR_SUCESS;\r
+       return hdmi;\r
 }\r
 \r
 #ifdef CONFIG_HAS_EARLYSUSPEND\r
index c7c9373878351c74f841202121c11686eff29b1d..ae72f2b47bcf284428998b8982eee45e6c6b520a 100755 (executable)
@@ -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));
index 3e7ed568e684e786a914994d76541da43a580e20..dcd730e3a7938b5078806e6fd4dc05dd6b0c66cd 100755 (executable)
@@ -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;