rk3066B: support rk610 hdmi.
authorZheng Yang <zhengyang@rock-chips.com>
Mon, 10 Sep 2012 06:12:30 +0000 (14:12 +0800)
committerZheng Yang <zhengyang@rock-chips.com>
Mon, 10 Sep 2012 06:12:30 +0000 (14:12 +0800)
18 files changed:
arch/arm/mach-rk30/board-rk3066b-m701.c [changed mode: 0644->0755]
arch/arm/mach-rk30/board-rk3066b-sdk.c
drivers/video/rockchip/hdmi/chips/Kconfig
drivers/video/rockchip/hdmi/chips/Makefile
drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.c
drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi.c
drivers/video/rockchip/hdmi/chips/rk610/Kconfig [new file with mode: 0755]
drivers/video/rockchip/hdmi/chips/rk610/Makefile [new file with mode: 0755]
drivers/video/rockchip/hdmi/chips/rk610/rk610_hdcp.c [new file with mode: 0755]
drivers/video/rockchip/hdmi/chips/rk610/rk610_hdcp.h [new file with mode: 0755]
drivers/video/rockchip/hdmi/chips/rk610/rk610_hdmi.c [new file with mode: 0755]
drivers/video/rockchip/hdmi/chips/rk610/rk610_hdmi.h [new file with mode: 0755]
drivers/video/rockchip/hdmi/chips/rk610/rk610_hdmi_hdcp.c [new file with mode: 0755]
drivers/video/rockchip/hdmi/chips/rk610/rk610_hdmi_hw.c [new file with mode: 0755]
drivers/video/rockchip/hdmi/chips/rk610/rk610_hdmi_hw.h [new file with mode: 0755]
drivers/video/rockchip/hdmi/rk_hdmi.h
drivers/video/rockchip/hdmi/rk_hdmi_sysfs.c
drivers/video/rockchip/hdmi/rk_hdmi_task.c

old mode 100644 (file)
new mode 100755 (executable)
index 9d7c8c1..19e31e7
@@ -1330,12 +1330,12 @@ static struct i2c_board_info __initdata i2c0_info[] = {
                        .flags                  = 0,
                },
 #endif
-#ifdef CONFIG_RK610_HDMI
+#ifdef CONFIG_HDMI_RK610
                {
                        .type                   = "rk610_hdmi",
                        .addr                   = 0x46,
                        .flags                  = 0,
-                       .irq                    = RK29_PIN5_PA2,
+                       .irq                    = INVALID_GPIO,
                },
 #endif
 #ifdef CONFIG_SND_SOC_RK610
index 3cc34d0074bb690b6b34a7eda676932f112d536c..ebfec737d24f12209686dfc6b1a44881cda5a732 100755 (executable)
@@ -1163,12 +1163,12 @@ static struct i2c_board_info __initdata i2c0_info[] = {
                        .flags                  = 0,
                },
 #endif
-#ifdef CONFIG_RK610_HDMI
+#ifdef CONFIG_HDMI_RK610
                {
                        .type                   = "rk610_hdmi",
                        .addr                   = 0x46,
                        .flags                  = 0,
-                       .irq                    = RK29_PIN5_PA2,
+                       .irq                    = INVALID_GPIO,
                },
 #endif
 #ifdef CONFIG_SND_SOC_RK610
index c01155675dccdd1bc920f17b366432d9a2b8ccef..75786166fdd21a87c141f5f29e6e1a89fda3bd23 100755 (executable)
@@ -1,21 +1,30 @@
-choice
-       prompt "HDMI chips select"
 config  HDMI_RK30
         bool "RK30 HDMI support"
         depends on LCDC_RK30
         help
            Support rk30 hdmi if you say y here
+
+if HDMI_RK30
+source "drivers/video/rockchip/hdmi/chips/rk30/Kconfig"
+endif
+
 config  HDMI_RK2928
         bool "RK2928 HDMI support"
         depends on LCDC_RK2928
         help
            Support rk2928 hdmi if you say y here
-endchoice
-
-if HDMI_RK30
-source "drivers/video/rockchip/hdmi/chips/rk30/Kconfig"
-endif
 
 if HDMI_RK2928
 source "drivers/video/rockchip/hdmi/chips/rk2928/Kconfig"
 endif
+
+config  HDMI_RK610
+        bool "RK610 HDMI support"
+        depends on MFD_RK610
+        help
+           Support rk610 hdmi if you say y here
+
+if HDMI_RK610
+source "drivers/video/rockchip/hdmi/chips/rk610/Kconfig"
+endif
+
index a43ac0633d6a12b3f0b1ae03422c8ca57f2241f0..38cb73e24fdad4c41e0ab5f5d90fe0ebcd56fd31 100755 (executable)
@@ -6,3 +6,4 @@ ccflags-$(CONFIG_HDMI_RK30_DEBUG) = -DDEBUG -DHDMI_DEBUG
 
 obj-$(CONFIG_HDMI_RK30) += rk30/
 obj-$(CONFIG_HDMI_RK2928) += rk2928/
+obj-$(CONFIG_HDMI_RK610) += rk610/
index 18f61087ce8a4a4ffb216076d63402771a4f7733..8a9926c4df03243a4cf58b754e50588a3c817d22 100755 (executable)
@@ -47,6 +47,10 @@ int rk2928_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),
 static void hdmi_early_suspend(struct early_suspend *h)\r
 {\r
        hdmi_dbg(hdmi->dev, "hdmi enter early suspend pwr %d state %d\n", hdmi->pwr_mode, hdmi->state);\r
+\r
+       rk30_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_GPIO0A7);\r
+       rk30_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_GPIO0A6);\r
+       \r
        flush_delayed_work(&hdmi->delay_work);  \r
        mutex_lock(&hdmi->enable_mutex);\r
        hdmi->suspend = 1;\r
@@ -63,10 +67,7 @@ static void hdmi_early_suspend(struct early_suspend *h)
        wait_for_completion_interruptible_timeout(&hdmi->complete,\r
                                                        msecs_to_jiffies(5000));\r
        flush_delayed_work(&hdmi->delay_work);\r
-       // When HDMI 1.1V and 2.5V power off, DDC channel will be pull down, current is produced\r
-       // from VCC_IO which is pull up outside soc. We need to switch DDC IO to GPIO.\r
-       rk30_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_GPIO0A7);\r
-       rk30_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_GPIO0A6);\r
+\r
        return;\r
 }\r
 \r
index 0aae519acc9e1edaea91ec3616fa36456944213d..aab3ecb4ee5484a1ca147220704316de1997fcab 100755 (executable)
@@ -47,6 +47,10 @@ int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),
 static void hdmi_early_suspend(struct early_suspend *h)\r
 {\r
        hdmi_dbg(hdmi->dev, "hdmi enter early suspend pwr %d state %d\n", hdmi->pwr_mode, hdmi->state);\r
+       // When HDMI 1.1V and 2.5V power off, DDC channel will be pull down, current is produced\r
+       // from VCC_IO which is pull up outside soc. We need to switch DDC IO to GPIO.\r
+       rk30_mux_api_set(GPIO0A2_HDMII2CSDA_NAME, GPIO0A_GPIO0A2);\r
+       rk30_mux_api_set(GPIO0A1_HDMII2CSCL_NAME, GPIO0A_GPIO0A1);\r
        flush_delayed_work(&hdmi->delay_work);  \r
        mutex_lock(&hdmi->enable_mutex);\r
        hdmi->suspend = 1;\r
@@ -63,10 +67,6 @@ static void hdmi_early_suspend(struct early_suspend *h)
        wait_for_completion_interruptible_timeout(&hdmi->complete,\r
                                                        msecs_to_jiffies(5000));\r
        flush_delayed_work(&hdmi->delay_work);\r
-       // When HDMI 1.1V and 2.5V power off, DDC channel will be pull down, current is produced\r
-       // from VCC_IO which is pull up outside soc. We need to switch DDC IO to GPIO.\r
-       rk30_mux_api_set(GPIO0A2_HDMII2CSDA_NAME, GPIO0A_GPIO0A2);\r
-       rk30_mux_api_set(GPIO0A1_HDMII2CSCL_NAME, GPIO0A_GPIO0A1);\r
        return;\r
 }\r
 \r
diff --git a/drivers/video/rockchip/hdmi/chips/rk610/Kconfig b/drivers/video/rockchip/hdmi/chips/rk610/Kconfig
new file mode 100755 (executable)
index 0000000..389f127
--- /dev/null
@@ -0,0 +1,14 @@
+config HDCP_RK610
+       bool "RK610 HDCP support"
+        depends on HDMI_RK610
+        default n
+       help
+         HDCP Interface. This adds the High Definition Content Protection Interface.
+         See http://www.digital-cp.com/ for HDCP specification.
+
+config HDCP_RK610_DEBUG
+       bool "RK610 HDCP Debugging"
+        depends on HDCP_RK610
+        default n
+       help
+         Enableds verbose debugging the the HDCP drivers
diff --git a/drivers/video/rockchip/hdmi/chips/rk610/Makefile b/drivers/video/rockchip/hdmi/chips/rk610/Makefile
new file mode 100755 (executable)
index 0000000..68750e2
--- /dev/null
@@ -0,0 +1,6 @@
+ccflags-$(CONFIG_RK_HDMI_DEBUG) = -DDEBUG -DHDMI_DEBUG
+ccflags-$(CONFIG_HDCP_RK2928_DEBUG) = -DHDCP_DEBUG
+
+obj-$(CONFIG_HDMI_RK610)               += rk610_hdmi_hw.o rk610_hdmi.o
+obj-$(CONFIG_HDCP_RK610)               += rk610_hdmi_hdcp.o rk610_hdcp.o
+
diff --git a/drivers/video/rockchip/hdmi/chips/rk610/rk610_hdcp.c b/drivers/video/rockchip/hdmi/chips/rk610/rk610_hdcp.c
new file mode 100755 (executable)
index 0000000..61207db
--- /dev/null
@@ -0,0 +1,563 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/miscdevice.h>
+#include <linux/workqueue.h>
+#include <linux/firmware.h>
+#include "rk610_hdmi.h"
+#include "rk610_hdcp.h"
+
+struct hdcp *hdcp = NULL;
+
+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 hdcp_delayed_work *work;
+
+       DBG("%s event %04x delay %d", __FUNCTION__, event, delay);
+       
+       work = kmalloc(sizeof(struct hdcp_delayed_work), GFP_ATOMIC);
+
+       if (work) {
+               INIT_DELAYED_WORK(&work->work, hdcp_work_queue);
+               work->event = event;
+               queue_delayed_work(hdcp->workqueue,
+                                  &work->work,
+                                  msecs_to_jiffies(delay));
+       } else {
+               printk(KERN_WARNING "HDCP: Cannot allocate memory to "
+                                   "create work\n");
+               return 0;
+       }
+
+       return &work->work;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_cancel_work
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_cancel_work(struct delayed_work **work)
+{
+       int ret = 0;
+
+       if (*work) {
+               ret = cancel_delayed_work(*work);
+               if (ret != 1) {
+                       ret = cancel_work_sync(&((*work)->work));
+                       printk(KERN_INFO "Canceling work failed - "
+                                        "cancel_work_sync done %d\n", ret);
+               }
+               kfree(*work);
+               *work = 0;
+       }
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_wq_authentication_failure
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_authentication_failure(void)
+{
+       if (hdcp->hdmi_state == HDMI_STOPPED) {
+               return;
+       }
+
+       rk610_hdcp_disable();
+       rk610_hdmi_sys_enalbe_output(false);
+       
+       hdcp_cancel_work(&hdcp->pending_wq_event);
+       
+       if (hdcp->retry_cnt && (hdcp->hdmi_state != HDMI_STOPPED)) {
+               if (hdcp->retry_cnt < HDCP_INFINITE_REAUTH) {
+                       hdcp->retry_cnt--;
+                       printk(KERN_INFO "HDCP: authentication failed - "
+                                        "retrying, attempts=%d\n",
+                                                       hdcp->retry_cnt);
+               } else
+                       printk(KERN_INFO "HDCP: authentication failed - "
+                                        "retrying\n");
+
+               hdcp->hdcp_state = HDCP_AUTHENTICATION_START;
+
+               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;
+       }
+
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_wq_start_authentication
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_start_authentication(void)
+{
+       int status = HDCP_OK;
+
+       hdcp->hdcp_state = HDCP_AUTHENTICATION_START;
+
+       DBG("HDCP: authentication start");
+
+       status = rk610_hdcp_start_authentication();
+
+       if (status != HDCP_OK) {
+               DBG("HDCP: authentication failed");
+               hdcp_wq_authentication_failure();
+       } else {
+               hdcp->hdcp_state = HDCP_WAIT_KSV_LIST;
+//             hdcp->hdcp_state = HDCP_LINK_INTEGRITY_CHECK;
+       }
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_wq_check_bksv
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_check_bksv(void)
+{
+       int status = HDCP_OK;
+
+       DBG("Check BKSV start");
+       
+       status = rk610_hdcp_check_bksv();
+
+       if (status != HDCP_OK) {
+               printk(KERN_INFO "HDCP: Check BKSV failed");
+               hdcp->retry_cnt = 0;
+               hdcp_wq_authentication_failure();
+       }
+       else {
+               DBG("HDCP: Check BKSV 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
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_authentication_sucess(void)
+{
+       rk610_hdmi_sys_enalbe_output(true);
+       printk(KERN_INFO "HDCP: authentication pass");
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_wq_disable
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_disable(int event)
+{
+       printk(KERN_INFO "HDCP: disabled");
+
+       hdcp_cancel_work(&hdcp->pending_wq_event);
+       rk610_hdcp_disable();
+       if(event == HDCP_DISABLE_CTL) {
+               hdcp->hdcp_state = HDCP_DISABLED;
+               if(hdcp->hdmi_state == HDMI_STARTED)
+                       rk610_hdmi_sys_enalbe_output(true);
+       }
+       else if(event == HDCP_STOP_FRAME_EVENT)
+               hdcp->hdcp_state = HDCP_ENABLE_PENDING;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_work_queue
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_work_queue(struct work_struct *work)
+{
+       struct hdcp_delayed_work *hdcp_w =
+               container_of(work, struct hdcp_delayed_work, work.work);
+       int event = hdcp_w->event;
+
+       mutex_lock(&hdcp->lock);
+       
+       DBG("hdcp_work_queue() - START - %u hdmi=%d hdcp=%d evt= %x %d",
+               jiffies_to_msecs(jiffies),
+               hdcp->hdmi_state,
+               hdcp->hdcp_state,
+               (event & 0xFF00) >> 8,
+               event & 0xFF);
+       
+       if(event == HDCP_STOP_FRAME_EVENT) {
+               hdcp->hdmi_state = HDMI_STOPPED;
+       }
+       
+       if (event == HDCP_DISABLE_CTL || event == HDCP_STOP_FRAME_EVENT) {
+               hdcp_wq_disable(event);
+       }
+       
+       if (event & HDCP_WORKQUEUE_SRC)
+               hdcp->pending_wq_event = 0;
+       
+       /* First handle HDMI state */
+       if (event == HDCP_START_FRAME_EVENT) {
+               hdcp->pending_start = 0;
+               hdcp->hdmi_state = HDMI_STARTED;
+       }
+       
+       /**********************/
+       /* HDCP state machine */
+       /**********************/
+       switch (hdcp->hdcp_state) {
+               case HDCP_DISABLED:
+                       /* HDCP enable control or re-authentication event */
+                       if (event == HDCP_ENABLE_CTL) {
+                               if(hdcp->retry_times == 0)
+                                       hdcp->retry_cnt = HDCP_INFINITE_REAUTH;
+                               else
+                                       hdcp->retry_cnt = hdcp->retry_times;
+                               if (hdcp->hdmi_state == HDMI_STARTED)
+                                       hdcp_wq_start_authentication();
+                               else
+                                       hdcp->hdcp_state = HDCP_ENABLE_PENDING;
+                       }
+                       break;
+               
+               case HDCP_ENABLE_PENDING:
+                       /* HDMI start frame event */
+                       if (event == HDCP_START_FRAME_EVENT)
+                               hdcp_wq_start_authentication();
+
+                       break;
+               
+               case HDCP_AUTHENTICATION_START:
+                       /* Re-authentication */
+                       if (event == HDCP_AUTH_REATT_EVENT)
+                               hdcp_wq_start_authentication();
+       
+                       break;
+               
+               case HDCP_WAIT_KSV_LIST:
+                       /* KSV failure */
+                       if (event == HDCP_FAIL_EVENT) {
+                               printk(KERN_INFO "HDCP: KSV switch failure\n");
+       
+                               hdcp_wq_authentication_failure();
+                       }
+                       /* KSV list ready event */
+                       else if (event == HDCP_KSV_LIST_RDY_EVENT)
+                               hdcp_wq_check_bksv();
+                       break;
+               
+               case HDCP_LINK_INTEGRITY_CHECK:
+                       /* Ri failure */
+                       if (event == HDCP_FAIL_EVENT) {
+                               printk(KERN_INFO "HDCP: Ri check failure\n");
+                               hdcp_wq_authentication_failure();
+                       }
+                       else if(event == HDCP_AUTH_PASS_EVENT)
+                               hdcp_wq_authentication_sucess();
+                       break;
+       
+               default:
+                       printk(KERN_WARNING "HDCP: error - unknow HDCP state\n");
+                       break;
+       }
+       
+       kfree(hdcp_w);
+       if(event == HDCP_STOP_FRAME_EVENT)
+               complete(&hdcp->complete);
+               
+       mutex_unlock(&hdcp->lock);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_start_frame_cb
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_start_frame_cb(void)
+{
+       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_start = hdcp_submit_work(HDCP_START_FRAME_EVENT,
+                                                       HDCP_ENABLE_DELAY);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_irq_cb
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_irq_cb(int status)
+{
+       char interrupt1;
+       char interrupt2;
+       
+       rk610_hdcp_interrupt(&interrupt1, &interrupt2);
+       DBG("%s 0x%02x 0x%02x", __FUNCTION__, interrupt1, interrupt2);
+       if(interrupt1 & m_INT_HDCP_ERR)
+       {
+               if( (hdcp->hdcp_state != HDCP_DISABLED) &&
+                       (hdcp->hdcp_state != HDCP_ENABLE_PENDING) )
+               {       
+                       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);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_power_on_cb
+ *-----------------------------------------------------------------------------
+ */
+static int hdcp_power_on_cb(void)
+{
+       DBG("%s", __FUNCTION__);
+//     return rk610_hdcp_load_key2mem(hdcp->keys);
+       return HDCP_OK;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_power_off_cb
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_power_off_cb(void)
+{
+       DBG("%s", __FUNCTION__);
+       if(!hdcp->enable)
+               return;
+       
+       hdcp_cancel_work(&hdcp->pending_start);
+       hdcp_cancel_work(&hdcp->pending_wq_event);
+       init_completion(&hdcp->complete);
+       /* Post event to workqueue */
+       if (hdcp_submit_work(HDCP_STOP_FRAME_EVENT, 0)) 
+               wait_for_completion_interruptible_timeout(&hdcp->complete,
+                                                       msecs_to_jiffies(5000));
+}
+
+// Load HDCP key to external HDCP memory
+static void hdcp_load_keys_cb(const struct firmware *fw, void *context)
+{
+       if (!fw) {
+               pr_err("HDCP: failed to load keys\n");
+               return;
+       }
+       
+       if(fw->size < HDCP_KEY_SIZE) {
+               pr_err("HDCP: firmware wrong size %d\n", fw->size);
+               return;
+       }
+       
+       hdcp->keys =  kmalloc(HDCP_KEY_SIZE, GFP_KERNEL);
+       if(hdcp->keys == NULL) {
+               pr_err("HDCP: can't allocated space for keys\n");
+               return;
+       }
+       
+       memcpy(hdcp->keys, fw->data, HDCP_KEY_SIZE);
+       
+       printk(KERN_INFO "HDCP: load hdcp key success\n");
+
+       if(fw->size > HDCP_KEY_SIZE) {
+               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;
+               }
+               hdcp->invalidkeys = kmalloc(fw->size - HDCP_KEY_SIZE, GFP_KERNEL);
+               if(hdcp->invalidkeys == NULL) {
+                       pr_err("HDCP: can't allocated space for invalid keys\n");
+                       return;
+               }
+               memcpy(hdcp->invalidkeys, fw->data + HDCP_KEY_SIZE, fw->size - HDCP_KEY_SIZE);
+               hdcp->invalidkey = (fw->size - HDCP_KEY_SIZE)/5;
+               printk(KERN_INFO "HDCP: loaded hdcp invalid key success\n");
+       }
+}
+
+static ssize_t hdcp_enable_read(struct device *device,
+                           struct device_attribute *attr, char *buf)
+{
+       int enable = 0;
+       
+       if(hdcp)
+               enable = hdcp->enable;
+               
+       return snprintf(buf, PAGE_SIZE, "%d\n", enable);
+}
+
+static ssize_t hdcp_enable_write(struct device *device,
+                          struct device_attribute *attr, const char *buf, size_t count)
+{
+       int enable;
+
+       if(hdcp == NULL)
+               return -EINVAL;
+       
+       sscanf(buf, "%d", &enable);
+       if(hdcp->enable != enable)
+       {
+               /* Post event to workqueue */
+               if(enable) {
+                       if (hdcp_submit_work(HDCP_ENABLE_CTL, 0) == 0)
+                               return -EFAULT;
+               }
+               else {
+                       hdcp_cancel_work(&hdcp->pending_start);
+                       hdcp_cancel_work(&hdcp->pending_wq_event);
+               
+                       /* Post event to workqueue */
+                       if (hdcp_submit_work(HDCP_DISABLE_CTL, 0) == 0)
+                               return -EFAULT;
+               }
+               hdcp->enable =  enable;
+       }
+       return count;
+}
+
+static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, hdcp_enable_read, hdcp_enable_write);
+
+static ssize_t hdcp_trytimes_read(struct device *device,
+                           struct device_attribute *attr, char *buf)
+{
+       int trytimes = 0;
+       
+       if(hdcp)
+               trytimes = hdcp->retry_times;
+               
+       return snprintf(buf, PAGE_SIZE, "%d\n", trytimes);
+}
+
+static ssize_t hdcp_trytimes_wrtie(struct device *device,
+                          struct device_attribute *attr, const char *buf, size_t count)
+{
+       int trytimes;
+
+       if(hdcp == NULL)
+               return -EINVAL;
+       
+       sscanf(buf, "%d", &trytimes);
+       if(hdcp->retry_times != trytimes)
+               hdcp->retry_times = trytimes;
+       
+       return count;
+}
+
+
+static DEVICE_ATTR(trytimes, S_IRUGO|S_IWUSR, hdcp_trytimes_read, hdcp_trytimes_wrtie);
+
+
+static struct miscdevice mdev;
+
+static int __init rk610_hdcp_init(void)
+{
+       int ret;
+       
+       DBG("[%s] %u", __FUNCTION__, jiffies_to_msecs(jiffies));
+       
+       hdcp = kmalloc(sizeof(struct hdcp), GFP_KERNEL);
+       if(!hdcp)
+       {
+       printk(KERN_ERR ">>HDCP: kmalloc fail!");
+       ret = -ENOMEM;
+       goto error0; 
+       }
+       memset(hdcp, 0, sizeof(struct hdcp));
+       mutex_init(&hdcp->lock);
+       
+       mdev.minor = MISC_DYNAMIC_MINOR;
+       mdev.name = "hdcp";
+       mdev.mode = 0666;
+       if (misc_register(&mdev)) {
+               printk(KERN_ERR "HDCP: Could not add character driver\n");
+               ret = HDMI_ERROR_FALSE;
+               goto error1;
+       }
+       ret = device_create_file(mdev.this_device, &dev_attr_enable);
+    if(ret)
+    {
+        printk(KERN_ERR "HDCP: Could not add sys file enable\n");
+        ret = -EINVAL;
+        goto error2;
+    }
+    
+    ret = device_create_file(mdev.this_device, &dev_attr_trytimes);
+    if(ret)
+    {
+        printk(KERN_ERR "HDCP: Could not add sys file trytimes\n");
+        ret = -EINVAL;
+        goto error3;
+    }
+    
+    hdcp->workqueue = create_singlethread_workqueue("hdcp");
+       if (hdcp->workqueue == NULL) {
+               printk(KERN_ERR "HDCP,: create workqueue failed.\n");
+               goto error4;
+       }
+    
+    
+    ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
+                             "hdcp.keys", mdev.this_device, GFP_KERNEL,
+                             hdcp, hdcp_load_keys_cb);
+       if (ret < 0) {
+               printk(KERN_ERR "HDCP: request_firmware_nowait failed: %d\n", ret);
+               goto error5;
+       }
+       
+       rk610_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));
+       return 0;
+       
+error5:
+       destroy_workqueue(hdcp->workqueue);
+error4:
+       device_remove_file(mdev.this_device, &dev_attr_trytimes);
+error3:
+       device_remove_file(mdev.this_device, &dev_attr_enable);
+error2:
+       misc_deregister(&mdev);
+error1:
+       if(hdcp->keys)
+               kfree(hdcp->keys);
+       if(hdcp->invalidkeys)
+               kfree(hdcp->invalidkeys);
+       kfree(hdcp);
+error0:
+       return ret;
+}
+
+static void __exit rk610_hdcp_exit(void)
+{
+       device_remove_file(mdev.this_device, &dev_attr_enable);
+       misc_deregister(&mdev);
+       if(hdcp->keys)
+               kfree(hdcp->keys);
+       if(hdcp->invalidkeys)
+               kfree(hdcp->invalidkeys);
+       kfree(hdcp);
+}
+
+module_init(rk610_hdcp_init);
+module_exit(rk610_hdcp_exit);
diff --git a/drivers/video/rockchip/hdmi/chips/rk610/rk610_hdcp.h b/drivers/video/rockchip/hdmi/chips/rk610/rk610_hdcp.h
new file mode 100755 (executable)
index 0000000..a33d1bc
--- /dev/null
@@ -0,0 +1,192 @@
+#ifndef __RK610_HDCP_H__
+#define __RK610_HDCP_H__
+
+/***************************/
+/* Definitions             */
+/***************************/
+
+/* Status / error codes */
+#define HDCP_OK                        0
+#define HDCP_KEY_ERR   1
+#define HDCP_KSV_ERR   2
+
+/* Delays */
+#define HDCP_ENABLE_DELAY      300
+#define HDCP_REAUTH_DELAY      100
+
+/* Event source */
+#define HDCP_SRC_SHIFT         8
+#define HDCP_IOCTL_SRC         (0x1 << HDCP_SRC_SHIFT)
+#define HDCP_HDMI_SRC          (0x2 << HDCP_SRC_SHIFT)
+#define HDCP_IRQ_SRC           (0x4 << HDCP_SRC_SHIFT)
+#define HDCP_WORKQUEUE_SRC     (0x8 << HDCP_SRC_SHIFT)
+
+/* Event */
+#define HDCP_ENABLE_CTL                        (HDCP_IOCTL_SRC         | 0)
+#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)
+
+/* Key size */
+#define HDCP_KEY_SIZE                  308     
+
+/* HDCP DDC Clock */
+#define HDCP_DDC_CLK                   100000
+
+/* Authentication retry times */
+#define HDCP_INFINITE_REAUTH   0x100
+
+/* HDCP Regs */
+#define HDCP_CTRL1                             0x52
+       #define m_AUTH_START            (1 << 7)
+       #define m_BKSV_VALID            (1 << 6)
+       #define m_BKSV_INVALID          (1 << 5)
+       #define m_ENCRYPT_ENABLE        (1 << 4)
+       #define m_AUTH_STOP                     (1 << 3)
+       #define m_ADVANED_ENABLE        (1 << 2)
+       #define m_HDMI_DVI                      (1 << 1)
+       #define m_HDCP_RESET            (1 << 0)
+       
+       #define v_AUTH_START(n)         (n << 7)
+       #define v_BKSV_VALID(n)         (n << 6)
+       #define v_BKSV_INVALID(n)       (n << 5)
+       #define v_ENCRYPT_ENABLE(n)     (n << 4)
+       #define v_AUTH_STOP(n)          (n << 3)
+       #define v_ADVANED_ENABLE(n)     (n << 2)
+       #define v_HDMI_DVI(n)           (n << 1)
+       #define v_HDCP_RESET(n)         (n << 0)
+
+#define HDCP_CTRL2                             0x53
+       #define m_DISABLE_127_CHECK                             (1 << 7)
+       #define m_SKIP_BKSV_CHECK                               (1 << 6)
+       #define m_ENABLE_PJ_CHECK                               (1 << 5)
+       #define m_DISABLE_DEVICE_NUMBER_CHECK   (1 << 4)
+       #define m_DELAY_RI_1_CLK                                (1 << 3)
+       #define m_USE_PRESET_AN                                 (1 << 2)
+       #define m_KEY_COMBINATION                               (3 << 0)
+       
+       #define v_DISABLE_127_CHECK(n)                  (n << 7)
+       #define v_SKIP_BKSV_CHECK(n)                    (n << 6)
+       #define v_ENABLE_PJ_CHECK(n)                    (n << 5)
+       #define v_DISABLE_DEVICE_NUMBER_CHECK(n)(n << 4)
+       #define v_DELAY_RI_1_CLK(n)                             (n << 3)
+       #define v_USE_PRESET_AN(n)                              (n << 2)
+       #define v_KEY_COMBINATION(n)                    (n << 0)
+
+#define HDCP_KEY_STATUS                        0x54
+       #define m_KEY_READY                     (1 << 0)
+
+#define HDCP_CTRL_SOFT                 0x57
+       #define m_DISABLE_127_CHECK                             (1 << 7)
+       #define m_SKIP_BKSV_CHECK                               (1 << 6)
+       #define m_NOT_AUTHENTICATED                             (1 << 5)
+       #define m_ENCRYPTED                                             (1 << 4)
+       #define m_ADVANCED_CIPHER                               (1 << 3)
+       
+#define HDCP_BCAPS_RX                  0x58
+#define HDCP_TIMER_100MS               0x63
+#define HDCP_TIMER_5S                  0x64
+#define HDCP_ERROR                             0x65
+       #define m_DDC_NO_ACK            (1 << 3)
+       #define m_PJ_MISMACH            (1 << 2)
+       #define m_RI_MISMACH            (1 << 1)
+       #define m_BKSV_WRONG            (1 << 0)
+
+#define HDCP_KSV_BYTE0                 0x66
+#define HDCP_KSV_BYTE1                 0x67
+#define HDCP_KSV_BYTE2                 0x68
+#define HDCP_KSV_BYTE3                 0x69
+#define HDCP_KSV_BYTE4                 0x6a
+
+#define HDCP_AN_SEED                   0x6c
+
+#define HDCP_BCAPS_TX                  0x80
+#define HDCP_BSTATE_0                  0x81
+#define HDCP_BSTATE_1                  0x82
+
+#define HDCP_KEY_FIFO                  0x98
+
+#define HDCP_INT_MASK1                 0xc2
+#define HDCP_INT_STATUS1               0xc3
+       #define m_INT_HDCP_ERR          (1 << 7)
+       #define m_INT_BKSV_READY        (1 << 6)
+       #define m_INT_BKSV_UPDATE       (1 << 5)
+       #define m_INT_AUTH_SUCCESS      (1 << 4)
+       #define m_INT_AUTH_READY        (1 << 3)
+       
+#define HDCP_INT_MASK2                 0xc4
+#define HDCP_INT_STATUS2               0xc5
+       #define m_INT_SOFT_MODE_READY                   (1 << 7)
+       #define m_INT_AUTH_M0_REDAY                             (1 << 6)
+       #define m_INT_1st_FRAME_ARRIVE                  (1 << 5)
+       #define m_INT_AN_READY                                  (1 << 4)
+       #define m_INT_ENCRYPTED                                 (1 << 2)
+       #define m_INT_NOT_ENCRYPTED_AVMUTE              (1 << 1)
+       #define m_INT_NOT_ENCRYPTED_AVUNMUTE    (1 << 0)
+
+enum hdcp_states {
+       HDCP_DISABLED,
+       HDCP_ENABLE_PENDING,
+       HDCP_AUTHENTICATION_START,
+       HDCP_WAIT_KSV_LIST,
+       HDCP_LINK_INTEGRITY_CHECK,
+};
+
+enum hdmi_states {
+       HDMI_STOPPED,
+       HDMI_STARTED
+};
+
+#define HDCP_PRIVATE_KEY_SIZE  280
+#define HDCP_KEY_SHA_SIZE              20
+
+struct hdcp_keys{
+       u8 KSV[8];
+       u8 DeviceKey[HDCP_PRIVATE_KEY_SIZE];
+       u8 sha1[HDCP_KEY_SHA_SIZE];
+};
+
+struct hdcp_delayed_work {
+       struct delayed_work work;
+       int event;
+};
+
+struct hdcp {
+       int     enable;
+       int retry_times;
+       struct hdcp_keys *keys;
+       int invalidkey;
+       char *invalidkeys;      
+       struct mutex lock;
+       struct completion       complete;
+       struct workqueue_struct *workqueue;
+       
+       enum hdmi_states hdmi_state;
+       enum hdcp_states hdcp_state;
+       
+       struct delayed_work *pending_start;
+       struct delayed_work *pending_wq_event;
+       int retry_cnt;
+};
+
+extern struct hdcp *hdcp;
+
+#define HDCP_DEBUG
+
+#ifdef HDCP_DEBUG
+#define DBG(format, ...) \
+               printk(KERN_INFO "HDCP: " format "\n", ## __VA_ARGS__)
+#else
+#define DBG(format, ...)
+#endif
+
+extern void rk610_hdcp_disable(void);
+extern int     rk610_hdcp_start_authentication(void);
+extern int     rk610_hdcp_check_bksv(void);
+extern int     rk610_hdcp_load_key2mem(struct hdcp_keys *key);
+extern void rk610_hdcp_interrupt(char *status1, char *status2);
+#endif /* __RK610_HDCP_H__ */
\ No newline at end of file
diff --git a/drivers/video/rockchip/hdmi/chips/rk610/rk610_hdmi.c b/drivers/video/rockchip/hdmi/chips/rk610/rk610_hdmi.c
new file mode 100755 (executable)
index 0000000..97fbb07
--- /dev/null
@@ -0,0 +1,281 @@
+#include <linux/kernel.h>\r
+#include <linux/delay.h>\r
+#include <linux/module.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/interrupt.h>\r
+#include <mach/gpio.h>\r
+#include <mach/iomux.h>\r
+#include <linux/i2c.h>\r
+#include "rk610_hdmi.h"\r
+\r
+struct rk610_hdmi_pdata *rk610_hdmi = NULL;\r
+struct hdmi *hdmi=NULL;\r
+\r
+extern struct rk_lcdc_device_driver * rk_get_lcdc_drv(char *name);\r
+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 rk610_hdmi_register_hdcp_callbacks(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
+{\r
+       hdmi->hdcp_cb = hdcp_cb;\r
+       hdmi->hdcp_irq_cb = hdcp_irq_cb;\r
+       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
+}\r
+\r
+#ifdef CONFIG_HAS_EARLYSUSPEND\r
+static void hdmi_early_suspend(struct early_suspend *h)\r
+{\r
+       hdmi_dbg(hdmi->dev, "hdmi enter early suspend pwr %d state %d\n", hdmi->pwr_mode, hdmi->state);\r
+       flush_delayed_work(&hdmi->delay_work);  \r
+       mutex_lock(&hdmi->enable_mutex);\r
+       hdmi->suspend = 1;\r
+       if(!hdmi->enable) {\r
+               mutex_unlock(&hdmi->enable_mutex);\r
+               return;\r
+       }\r
+       \r
+       #ifdef HDMI_USE_IRQ\r
+       if(hdmi->irq)\r
+               disable_irq(hdmi->irq);\r
+       #endif\r
+       \r
+       mutex_unlock(&hdmi->enable_mutex);\r
+       hdmi->command = HDMI_CONFIG_ENABLE;\r
+       init_completion(&hdmi->complete);\r
+       hdmi->wait = 1;\r
+       queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, 0);\r
+       wait_for_completion_interruptible_timeout(&hdmi->complete,\r
+                                                       msecs_to_jiffies(5000));\r
+       flush_delayed_work(&hdmi->delay_work);\r
+       return;\r
+}\r
+\r
+static void hdmi_early_resume(struct early_suspend *h)\r
+{\r
+       hdmi_dbg(hdmi->dev, "hdmi exit early resume\n");\r
+       mutex_lock(&hdmi->enable_mutex);\r
+       \r
+       hdmi->suspend = 0;\r
+       #ifdef HDMI_USE_IRQ\r
+       if(hdmi->enable && hdmi->irq) {\r
+               enable_irq(hdmi->irq);\r
+       }\r
+       #else\r
+       queue_delayed_work(rk610_hdmi->workqueue, &rk610_hdmi->delay_work, 100);\r
+       #endif\r
+       queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10));   \r
+       mutex_unlock(&hdmi->enable_mutex);\r
+       return;\r
+}\r
+#endif\r
+\r
+static void rk610_irq_work_func(struct work_struct *work)\r
+{\r
+       if(hdmi->suspend == 0) {\r
+               if(hdmi->enable == 1) {\r
+                       rk610_hdmi_interrupt();\r
+                       if(hdmi->hdcp_irq_cb)\r
+                               hdmi->hdcp_irq_cb(0);\r
+               }\r
+               #ifndef HDMI_USE_IRQ\r
+               queue_delayed_work(rk610_hdmi->workqueue, &rk610_hdmi->delay_work, 50);\r
+               #endif\r
+       }\r
+}\r
+\r
+#ifdef HDMI_USE_IRQ\r
+static irqreturn_t rk610_irq(int irq, void *dev_id)\r
+{\r
+       printk(KERN_INFO "rk610 irq triggered.\n");\r
+       schedule_work(&rk610_hdmi->irq_work);\r
+    return IRQ_HANDLED;\r
+}\r
+#endif\r
+\r
+static int rk610_hdmi_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id)\r
+{\r
+    int rc = 0;\r
+       \r
+       rk610_hdmi = kzalloc(sizeof(struct rk610_hdmi_pdata), GFP_KERNEL);\r
+       if(!rk610_hdmi)\r
+       {\r
+        dev_err(&client->dev, "no memory for state\n");\r
+       return -ENOMEM;\r
+    }\r
+       rk610_hdmi->client = client;\r
+       i2c_set_clientdata(client, rk610_hdmi);\r
+       \r
+       hdmi = kmalloc(sizeof(struct hdmi), GFP_KERNEL);\r
+       if(!hdmi)\r
+       {\r
+       dev_err(&client->dev, "rk610 hdmi kmalloc fail!");\r
+       goto err_kzalloc_hdmi;\r
+       }\r
+       memset(hdmi, 0, sizeof(struct hdmi));\r
+       hdmi->dev = &client->dev;\r
+       \r
+       if(HDMI_SOURCE_DEFAULT == HDMI_SOURCE_LCDC0)\r
+               hdmi->lcdc = rk_get_lcdc_drv("lcdc0");\r
+       else\r
+               hdmi->lcdc = rk_get_lcdc_drv("lcdc1");\r
+       if(hdmi->lcdc == NULL)\r
+       {\r
+               dev_err(hdmi->dev, "can not connect to video source lcdc\n");\r
+               rc = -ENXIO;\r
+               goto err_request_lcdc;\r
+       }\r
+       hdmi->xscale = 95;\r
+       hdmi->yscale = 95;\r
+       hdmi->insert = rk610_hdmi_sys_insert;\r
+       hdmi->remove = rk610_hdmi_sys_remove;\r
+       hdmi->control_output = rk610_hdmi_sys_enalbe_output;\r
+       hdmi->config_video = rk610_hdmi_sys_config_video;\r
+       hdmi->config_audio = rk610_hdmi_sys_config_audio;\r
+       hdmi->detect_hotplug = rk610_hdmi_sys_detect_hpd;\r
+       hdmi->read_edid = rk610_hdmi_sys_read_edid;\r
+       hdmi_sys_init();\r
+       \r
+       hdmi->workqueue = create_singlethread_workqueue("hdmi");\r
+       INIT_DELAYED_WORK(&(hdmi->delay_work), hdmi_work);\r
+       \r
+       #ifdef CONFIG_HAS_EARLYSUSPEND\r
+       hdmi->early_suspend.suspend = hdmi_early_suspend;\r
+       hdmi->early_suspend.resume = hdmi_early_resume;\r
+       hdmi->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 10;\r
+       register_early_suspend(&hdmi->early_suspend);\r
+       #endif\r
+       \r
+       hdmi_register_display_sysfs(hdmi, NULL);\r
+       #ifdef CONFIG_SWITCH\r
+       hdmi->switch_hdmi.name="hdmi";\r
+       switch_dev_register(&(hdmi->switch_hdmi));\r
+       #endif\r
+               \r
+       spin_lock_init(&hdmi->irq_lock);\r
+       mutex_init(&hdmi->enable_mutex);\r
+       \r
+       rk610_hdmi_sys_init();\r
+       \r
+#ifdef HDMI_USE_IRQ\r
+       if(client->irq != INVALID_GPIO) {\r
+               INIT_WORK(&rk610_hdmi->irq_work, rk610_irq_work_func);\r
+               if((rc = gpio_request(client->irq, "hdmi gpio")) < 0)\r
+           {\r
+               dev_err(&client->dev, "fail to request gpio %d\n", client->irq);\r
+               goto err_request_lcdc;\r
+           }\r
+           hdmi->irq = gpio_to_irq(client->irq);\r
+               rk610_hdmi->gpio = client->irq;\r
+           gpio_pull_updown(client->irq, GPIOPullUp);\r
+           gpio_direction_input(client->irq);\r
+           if((rc = request_irq(rk610_hdmi->irq, rk610_irq, IRQF_TRIGGER_RISING, NULL, hdmi)) < 0)\r
+           {\r
+               dev_err(&client->dev, "fail to request hdmi irq\n");\r
+               goto err_request_irq;\r
+           }\r
+       }\r
+       else\r
+#else\r
+       {\r
+               rk610_hdmi->workqueue = create_singlethread_workqueue("rk610 irq");\r
+               INIT_DELAYED_WORK(&(rk610_hdmi->delay_work), rk610_irq_work_func);\r
+               rk610_irq_work_func(NULL);\r
+       }\r
+#endif\r
+\r
+       dev_info(&client->dev, "rk610 hdmi i2c probe ok\n");\r
+       \r
+    return 0;\r
+       \r
+err_request_irq:\r
+       gpio_free(client->irq);\r
+err_request_lcdc:\r
+       kfree(hdmi);\r
+       hdmi = NULL;\r
+err_kzalloc_hdmi:\r
+       kfree(rk610_hdmi);\r
+       rk610_hdmi = NULL;\r
+       dev_err(&client->dev, "rk610 hdmi probe error\n");\r
+       return rc;\r
+\r
+}\r
+\r
+static int __devexit rk610_hdmi_i2c_remove(struct i2c_client *client)\r
+{      \r
+       hdmi_dbg(hdmi->dev, "%s\n", __func__);\r
+       if(hdmi) {\r
+               mutex_lock(&hdmi->enable_mutex);\r
+               if(!hdmi->suspend && hdmi->enable && hdmi->irq)\r
+                       disable_irq(hdmi->irq);\r
+               mutex_unlock(&hdmi->enable_mutex);\r
+               if(hdmi->irq)\r
+                       free_irq(hdmi->irq, NULL);\r
+               flush_workqueue(hdmi->workqueue);\r
+               destroy_workqueue(hdmi->workqueue);\r
+               #ifdef CONFIG_SWITCH\r
+               switch_dev_unregister(&(hdmi->switch_hdmi));\r
+               #endif\r
+               hdmi_unregister_display_sysfs(hdmi);\r
+               #ifdef CONFIG_HAS_EARLYSUSPEND\r
+               unregister_early_suspend(&hdmi->early_suspend);\r
+               #endif\r
+               fb_destroy_modelist(&hdmi->edid.modelist);\r
+               if(hdmi->edid.audio)\r
+                       kfree(hdmi->edid.audio);\r
+               if(hdmi->edid.specs)\r
+               {\r
+                       if(hdmi->edid.specs->modedb)\r
+                               kfree(hdmi->edid.specs->modedb);\r
+                       kfree(hdmi->edid.specs);\r
+               }\r
+               kfree(hdmi);\r
+               hdmi = NULL;\r
+       }\r
+    return 0;\r
+}\r
+\r
+static void rk610_hdmi_i2c_shutdown(struct i2c_client *client)\r
+{\r
+       if(hdmi) {\r
+               #ifdef CONFIG_HAS_EARLYSUSPEND\r
+               unregister_early_suspend(&hdmi->early_suspend);\r
+               #endif\r
+       }\r
+       printk(KERN_INFO "rk610 hdmi shut down.\n");\r
+}\r
+\r
+static const struct i2c_device_id rk610_hdmi_id[] = {\r
+       { "rk610_hdmi", 0 },\r
+       { }\r
+};\r
+\r
+static struct i2c_driver rk610_hdmi_i2c_driver = {\r
+    .driver = {\r
+        .name  = "rk610_hdmi",\r
+        .owner = THIS_MODULE,\r
+    },\r
+    .probe      = rk610_hdmi_i2c_probe,\r
+    .remove     = rk610_hdmi_i2c_remove,\r
+    .shutdown  = rk610_hdmi_i2c_shutdown,\r
+    .id_table  = rk610_hdmi_id,\r
+};\r
+\r
+static int __init rk610_hdmi_init(void)\r
+{\r
+    return i2c_add_driver(&rk610_hdmi_i2c_driver);\r
+}\r
+\r
+static void __exit rk610_hdmi_exit(void)\r
+{\r
+    i2c_del_driver(&rk610_hdmi_i2c_driver);\r
+}\r
+\r
+module_init(rk610_hdmi_init);\r
+//fs_initcall(rk610_init);\r
+module_exit(rk610_hdmi_exit);\r
diff --git a/drivers/video/rockchip/hdmi/chips/rk610/rk610_hdmi.h b/drivers/video/rockchip/hdmi/chips/rk610/rk610_hdmi.h
new file mode 100755 (executable)
index 0000000..5ddd8ae
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __RK610_HDMI_H__\r
+#define __RK610_HDMI_H__\r
+#include "../../rk_hdmi.h"\r
+\r
+#define HDMI_SOURCE_DEFAULT HDMI_SOURCE_LCDC0\r
+\r
+struct rk610_hdmi_pdata {\r
+       int gpio;\r
+       struct i2c_client *client;\r
+       struct delayed_work delay_work;\r
+       #ifndef HDMI_USE_IRQ\r
+       struct workqueue_struct *workqueue;\r
+       #endif\r
+};\r
+\r
+extern struct rk610_hdmi_pdata *rk610_hdmi;\r
+\r
+extern int rk610_hdmi_sys_init(void);\r
+extern void rk610_hdmi_interrupt(void);\r
+extern int rk610_hdmi_sys_detect_hpd(void);\r
+extern int rk610_hdmi_sys_insert(void);\r
+extern int rk610_hdmi_sys_remove(void);\r
+extern int rk610_hdmi_sys_read_edid(int block, unsigned char *buff);\r
+extern int rk610_hdmi_sys_config_video(struct hdmi_video_para *vpara);\r
+extern int rk610_hdmi_sys_config_audio(struct hdmi_audio *audio);\r
+extern void rk610_hdmi_sys_enalbe_output(int enable);\r
+extern int rk610_hdmi_register_hdcp_callbacks(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
+#endif\r
diff --git a/drivers/video/rockchip/hdmi/chips/rk610/rk610_hdmi_hdcp.c b/drivers/video/rockchip/hdmi/chips/rk610/rk610_hdmi_hdcp.c
new file mode 100755 (executable)
index 0000000..e690f71
--- /dev/null
@@ -0,0 +1,156 @@
+#include <linux/delay.h>\r
+#include "rk610_hdmi.h"\r
+#include "rk610_hdmi_hw.h"\r
+#include "rk610_hdcp.h"\r
+\r
+static char rk610_hdmi_i2c_read_reg(char reg)\r
+{\r
+       char val = 0;\r
+       \r
+       if(i2c_master_reg8_recv(rk610_hdmi->client, reg, &val, 1, 100*1000) > 0)\r
+               return  val;\r
+       else {\r
+               printk(KERN_ERR "[%s] read reg %02x error\n", __FUNCTION__, reg);\r
+               return 0;\r
+       }\r
+}\r
+static char rk610_hdmi_i2c_write_reg(char reg, char val)\r
+{\r
+       if(i2c_master_reg8_send(rk610_hdmi->client, reg, &val, 1, 100*1000) > 0)\r
+               return 0;\r
+       else {\r
+               printk(KERN_ERR "[%s] write reg %02x error\n", __FUNCTION__, reg);\r
+               return -EINVAL;\r
+       }\r
+}\r
+\r
+#define HDCPWrReg      rk610_hdmi_i2c_write_reg\r
+#define HDCPRdReg      rk610_hdmi_i2c_read_reg\r
+#define HDCPMskReg(temp, addr, msk, val)       \\r
+       temp = HDCPRdReg(addr) & (0xFF - (msk)) ; \\r
+       HDCPWrReg(addr, temp | ( (val) & (msk) )); \r
+       \r
+void rk610_hdcp_disable(void)\r
+{\r
+       char temp;\r
+       \r
+       // Diable HDCP Interrupt\r
+       HDCPWrReg(HDCP_INT_MASK1, 0x00);\r
+       // Stop and Reset HDCP\r
+       HDCPMskReg(temp, HDCP_CTRL1, m_ENCRYPT_ENABLE | m_AUTH_STOP | m_HDCP_RESET, \r
+               v_ENCRYPT_ENABLE(0) | v_AUTH_STOP(1) | v_HDCP_RESET(1) )\r
+}\r
+\r
+int    rk610_hdcp_load_key2mem(struct hdcp_keys *key)\r
+{\r
+       int i;\r
+       DBG("HDCP: rk610_hdcp_load_key2mem start");\r
+       // Write 40 private key\r
+       for(i = 0; i < HDCP_PRIVATE_KEY_SIZE; i++)\r
+               HDCPWrReg(HDCP_KEY_FIFO, key->DeviceKey[i]);\r
+       \r
+       // Write 1st aksv\r
+       for(i = 0; i < 5; i++)\r
+               HDCPWrReg(HDCP_KEY_FIFO, key->KSV[i]);\r
+               \r
+       // Write 2nd aksv\r
+       for(i = 0; i < 5; i++)\r
+               HDCPWrReg(HDCP_KEY_FIFO, key->KSV[i]);\r
+       DBG("HDCP: rk610_hdcp_load_key2mem end");\r
+       return HDCP_OK;\r
+}\r
+\r
+int    rk610_hdcp_start_authentication(void)\r
+{\r
+       char temp;\r
+       int retry = 0;\r
+\r
+       if(hdcp->keys == NULL) {\r
+               printk(KERN_ERR "HDCP: key is not loaded\n");\r
+               return HDCP_KEY_ERR;\r
+       }\r
+       \r
+       // Select TMDS CLK to configure regs\r
+       HDCPMskReg(temp, SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_TMDS);\r
+       \r
+       temp = HDCPRdReg(HDCP_KEY_STATUS);\r
+       while( ( temp & m_KEY_READY) == 0 ) {\r
+               if(retry > 10) {\r
+                       printk(KERN_ERR "HDCP: loaded key error\n");\r
+                       return HDCP_KEY_ERR;\r
+               }\r
+               rk610_hdcp_load_key2mem(hdcp->keys);\r
+               msleep(1);\r
+               temp = HDCPRdReg(HDCP_KEY_STATUS);\r
+       }\r
+       \r
+       // Config DDC bus clock: ddc_clk = reg_clk/4*(reg 0x4c 0x4b)\r
+       DBG("TMDS frequency %d", hdmi->tmdsclk);\r
+       retry = hdmi->tmdsclk/(HDCP_DDC_CLK*4);\r
+       HDCPWrReg(DDC_CLK_L, retry & 0xFF);\r
+       HDCPWrReg(DDC_CLK_H, (retry >> 8) & 0xFF);\r
+       \r
+       HDCPWrReg(HDCP_CTRL2, 0x00);\r
+       \r
+       //Enable interrupt\r
+       HDCPWrReg(HDCP_INT_MASK1, m_INT_HDCP_ERR | m_INT_BKSV_READY | m_INT_BKSV_UPDATE | m_INT_AUTH_SUCCESS | m_INT_AUTH_READY);\r
+//     HDCPWrReg(HDCP_INT_MASK2, 0xFF);\r
+       //Start authentication\r
+       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));\r
+       \r
+       return HDCP_OK;\r
+}\r
+\r
+int    rk610_hdcp_check_bksv(void)\r
+{\r
+       int i, j;\r
+       char temp = 0, bksv[5];\r
+       char *invalidkey;\r
+       \r
+       for(i = 0; i < 5; i++) {\r
+               bksv[i] = HDCPRdReg(HDCP_KSV_BYTE0 + (4 - i)) & 0xFF;\r
+       }\r
+       DBG("bksv is 0x%02x%02x%02x%02x%02x", bksv[0], bksv[1], bksv[2], bksv[3], bksv[4]);\r
+       \r
+       for (i = 0; i < 5; i++)\r
+       {\r
+       for (j = 0; j < 8; j++)\r
+       {\r
+               if (bksv[i] & 0x01)\r
+               {\r
+                       temp++;\r
+               }\r
+               bksv[i] >>= 1;\r
+       }\r
+       }\r
+       if (temp != 20)\r
+       return HDCP_KSV_ERR;\r
+       \r
+       for(i = 0; i < hdcp->invalidkey; i++)\r
+       {\r
+               invalidkey = hdcp->invalidkeys + i *5;\r
+               if(memcmp(bksv, invalidkey, 5) == 0) {\r
+                       printk(KERN_ERR "HDCP: BKSV was revocated!!!\n");\r
+                       HDCPMskReg(temp, HDCP_CTRL1, m_BKSV_INVALID | m_ENCRYPT_ENABLE, v_BKSV_INVALID(1) | v_ENCRYPT_ENABLE(1));\r
+                       return HDCP_KSV_ERR;\r
+               }\r
+       }\r
+       HDCPMskReg(temp, HDCP_CTRL1, m_BKSV_VALID | m_ENCRYPT_ENABLE, v_BKSV_VALID(1) | v_ENCRYPT_ENABLE(1));\r
+       return HDCP_OK;\r
+}\r
+\r
+void rk610_hdcp_interrupt(char *status1, char *status2)\r
+{\r
+       char interrupt1 = HDCPRdReg(HDCP_INT_STATUS1);\r
+       char interrupt2 = HDCPRdReg(HDCP_INT_STATUS2);\r
+       if(interrupt1) {\r
+               HDCPWrReg(HDCP_INT_STATUS1, interrupt1);\r
+               if(interrupt1 & m_INT_HDCP_ERR)\r
+                       printk(KERN_INFO "HDCP: Error 0x%02x\n", HDCPRdReg(HDCP_ERROR));\r
+       }\r
+       if(interrupt2)\r
+               HDCPWrReg(HDCP_INT_STATUS2, interrupt2);\r
+       \r
+       *status1 = interrupt1;\r
+       *status2 = interrupt2;\r
+}
\ No newline at end of file
diff --git a/drivers/video/rockchip/hdmi/chips/rk610/rk610_hdmi_hw.c b/drivers/video/rockchip/hdmi/chips/rk610/rk610_hdmi_hw.c
new file mode 100755 (executable)
index 0000000..9c3396f
--- /dev/null
@@ -0,0 +1,409 @@
+#include <linux/delay.h>\r
+#include "rk610_hdmi.h"\r
+#include "rk610_hdmi_hw.h"\r
+#include <asm/atomic.h>\r
+\r
+static atomic_t edid_ready;\r
+\r
+static int rk610_hdmi_i2c_read_reg(char reg, char *val)\r
+{\r
+       if(i2c_master_reg8_recv(rk610_hdmi->client, reg, val, 1, 100*1000) > 0)\r
+               return  0;\r
+       else {\r
+               printk("[%s] reg %02x error\n", __FUNCTION__, reg);\r
+               return -EINVAL;\r
+       }\r
+}\r
+static int rk610_hdmi_i2c_write_reg(char reg, char val)\r
+{\r
+       return i2c_master_reg8_send(rk610_hdmi->client, reg, &val, 1, 100*1000) > 0? 0: -EINVAL;\r
+}\r
+\r
+#define HDMIWrReg      rk610_hdmi_i2c_write_reg\r
+\r
+int rk610_hdmi_sys_init(void)\r
+{\r
+       // System power power off\r
+       HDMIWrReg(SYS_CTRL, v_REG_CLK_SOURCE_IIS | v_PWR_OFF | v_INT_POL_HIGH);\r
+       \r
+       //Synchronize analog module.\r
+//     HDMIWrReg(PHY_SYNC, 0x00);\r
+//     HDMIWrReg(PHY_SYNC, 0x01);\r
+       \r
+       // set hdmi phy parameters\r
+       // driver mode\r
+       HDMIWrReg(PHY_DRIVER, v_MAIN_DRIVER(8)| v_PRE_DRIVER(0) | v_TX_ENABLE(0));\r
+//     HDMIWrReg(PHY_PRE_EMPHASIS, 0x04);\r
+       HDMIWrReg(PHY_PRE_EMPHASIS, v_PRE_EMPHASIS(0) | v_TMDS_PWRDOWN(1));     //Driver power down     \r
+       // pll mode\r
+       HDMIWrReg(0xe8, 0x10);\r
+       HDMIWrReg(0xe6, 0x2c);\r
+\r
+       HDMIWrReg(PHY_PLL_CTRL, v_PLL_DISABLE(1) | v_PLL_RESET(1) | v_TMDS_RESET(1));\r
+       HDMIWrReg(PHY_PLL_LDO_PWR, v_LDO_PWR_DOWN(1));\r
+       HDMIWrReg(PHY_BANDGAP_PWR, v_BANDGAP_PWR_DOWN);\r
+\r
+       // Enable Hotplug interrupt\r
+       HDMIWrReg(INTERRUPT_MASK1, m_INT_HOTPLUG);\r
+       return HDMI_ERROR_SUCESS;\r
+}\r
+\r
+void rk610_hdmi_interrupt()\r
+{\r
+       char interrupt = 0;\r
+       \r
+       if(rk610_hdmi_i2c_read_reg(INTERRUPT_STATUS1, &interrupt))\r
+               return;\r
+               \r
+       HDMIWrReg(INTERRUPT_STATUS1, interrupt);\r
+       \r
+       if(interrupt)\r
+               HDMIWrReg(INTERRUPT_STATUS1, interrupt);\r
+       \r
+       if(interrupt & m_INT_HOTPLUG) {\r
+               hdmi_dbg(hdmi->dev, "%s interrupt %02x\n", __FUNCTION__, interrupt);\r
+               if(hdmi->state == HDMI_SLEEP)\r
+                       hdmi->state = WAIT_HOTPLUG;\r
+               queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10));   \r
+       }\r
+       else if(interrupt & m_INT_EDID_READY) {\r
+               atomic_set(&edid_ready, 1);\r
+       }\r
+}\r
+\r
+int rk610_hdmi_sys_detect_hpd(void)\r
+{\r
+       char hdmi_status = 0;\r
+\r
+       #ifdef HDMI_USE_IRQ\r
+       rk610_hdmi_i2c_read_reg(INTERRUPT_STATUS1, &hdmi_status);\r
+       HDMIWrReg(INTERRUPT_STATUS1, hdmi_status);\r
+       #endif\r
+       hdmi_status = 0;\r
+       rk610_hdmi_i2c_read_reg(HDMI_STATUS, &hdmi_status);\r
+//     printk("%s value is %02x\n", __FUNCTION__, hdmi_status);        \r
+       if(hdmi_status)\r
+               return HDMI_HPD_ACTIVED;\r
+       else\r
+               return HDMI_HPD_REMOVED;\r
+}\r
+\r
+#define SYSCLK 11289600\r
+#define DDC_CLK 100000\r
+int rk610_hdmi_sys_read_edid(int block, unsigned char *buff)\r
+{\r
+       char value;\r
+       int count, rc = HDMI_ERROR_EDID;\r
+       int trytime = 2;\r
+       \r
+       // Config DDC bus clock: ddc_clk = reg_clk/4*(reg 0x4c 0x4b)\r
+       // when reg00 select reg_clk equal to sys_clk which is equal\r
+       // to i2s clk, it gernerally is 11.2896MHz.\r
+       \r
+       count = SYSCLK/(DDC_CLK*4);\r
+       HDMIWrReg(DDC_CLK_L, count & 0xFF);\r
+       HDMIWrReg(DDC_CLK_H, (count >> 8) & 0xFF);\r
+       \r
+       // Enable EDID Interrupt\r
+//     edid_ready = 0;\r
+       atomic_set(&edid_ready, 0);\r
+       value = 0;\r
+       rk610_hdmi_i2c_read_reg(INTERRUPT_MASK1, &value);\r
+       value |= m_INT_EDID_READY;\r
+       HDMIWrReg(INTERRUPT_MASK1, value);\r
+       \r
+       \r
+       while(trytime--) {\r
+               // Reset FIFO offset\r
+               HDMIWrReg(EDID_FIFO_OFFSET, 0);\r
+               // Set EDID read addr.\r
+               HDMIWrReg(EDID_WORD_ADDR, (block%2) * 0x80);\r
+               HDMIWrReg(EDID_SEGMENT_POINTER, block/2);\r
+               \r
+               count = 0;\r
+               while(count++ < 10)\r
+               {       \r
+                       value = atomic_read(&edid_ready);\r
+                       if(value)\r
+                       {\r
+                               for(count = 0; count < 128; count++)\r
+                                       rk610_hdmi_i2c_read_reg(EDID_FIFO_ADDR, buff + count);\r
+                               rc = HDMI_ERROR_SUCESS;\r
+                               break;\r
+                       }\r
+                       msleep(100);\r
+               }\r
+       }\r
+       // Disable EDID interrupt.\r
+       value = 0;\r
+       rk610_hdmi_i2c_read_reg(INTERRUPT_MASK1, &value);\r
+       value &= ~m_INT_EDID_READY;\r
+       HDMIWrReg(INTERRUPT_MASK1, value);\r
+       return rc;\r
+}\r
+\r
+static void rk610_hdmi_config_avi(unsigned char vic, unsigned char output_color)\r
+{\r
+       int i;\r
+       char info[SIZE_AVI_INFOFRAME];\r
+       \r
+       memset(info, 0, SIZE_AVI_INFOFRAME);\r
+       HDMIWrReg(CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI);\r
+       info[0] = 0x82;\r
+       info[1] = 0x02;\r
+       info[2] = 0x0D; \r
+       info[3] = info[0] + info[1] + info[2];\r
+       info[4] = (AVI_COLOR_MODE_RGB << 5);\r
+       info[5] = (AVI_COLORIMETRY_NO_DATA << 6) | (AVI_CODED_FRAME_ASPECT_NO_DATA << 4) | ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME;\r
+       info[6] = 0;\r
+       info[7] = vic;\r
+       info[8] = 0;\r
+\r
+       // Calculate AVI InfoFrame ChecKsum\r
+       for (i = 4; i < SIZE_AVI_INFOFRAME; i++)\r
+       {\r
+       info[3] += info[i];\r
+       }\r
+       info[3] = 0x100 - info[3];\r
+       \r
+       for(i = 0; i < SIZE_AVI_INFOFRAME; i++)\r
+               HDMIWrReg(CONTROL_PACKET_ADDR + i, info[i]);\r
+}\r
+\r
+int rk610_hdmi_sys_config_video(struct hdmi_video_para *vpara)\r
+{\r
+       char value;\r
+       struct fb_videomode *mode;\r
+       \r
+       hdmi_dbg(hdmi->dev, "[%s]\n", __FUNCTION__);\r
+       if(vpara == NULL) {\r
+               hdmi_err(hdmi->dev, "[%s] input parameter error\n", __FUNCTION__);\r
+               return -1;\r
+       }\r
+       if(hdmi->hdcp_power_off_cb)\r
+               hdmi->hdcp_power_off_cb();\r
+       // Diable video and audio output\r
+       HDMIWrReg(AV_MUTE, v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1));\r
+       \r
+       // Input video mode is SDR RGB24bit, Data enable signal from external\r
+       HDMIWrReg(VIDEO_CONTRL1, v_VIDEO_INPUT_FORMAT(VIDEO_INPUT_SDR_RGB444) | v_DE_EXTERNAL);\r
+       HDMIWrReg(VIDEO_CONTRL2, v_VIDEO_INPUT_BITS(VIDEO_INPUT_8BITS) | (vpara->output_color & 0xFF));\r
+\r
+       // Set HDMI Mode\r
+       HDMIWrReg(HDCP_CTRL, v_HDMI_DVI(vpara->output_mode));\r
+\r
+       // Enable or disalbe color space convert\r
+       if(vpara->input_color != vpara->output_color) {\r
+               value = v_SOF_DISABLE | v_CSC_ENABLE;\r
+       }\r
+       else\r
+               value = v_SOF_DISABLE;\r
+       HDMIWrReg(VIDEO_CONTRL3, value);\r
+       \r
+       #if 1\r
+       HDMIWrReg(VIDEO_TIMING_CTL, 0);\r
+       mode = (struct fb_videomode *)hdmi_vic_to_videomode(vpara->vic);\r
+       if(mode == NULL)\r
+       {\r
+               hdmi_err(hdmi->dev, "[%s] not found vic %d\n", __FUNCTION__, vpara->vic);\r
+               return -ENOENT;\r
+       }\r
+       hdmi->tmdsclk = mode->pixclock;\r
+#else\r
+       value = v_EXTERANL_VIDEO(1) | v_INETLACE(mode->vmode);\r
+       if(mode->sync & FB_SYNC_HOR_HIGH_ACT)\r
+               value |= v_HSYNC_POLARITY(1);\r
+       if(mode->sync & FB_SYNC_VERT_HIGH_ACT)\r
+               value |= v_VSYNC_POLARITY(1);\r
+       HDMIWrReg(VIDEO_TIMING_CTL, value);\r
+       \r
+       value = mode->left_margin + mode->xres + mode->right_margin + mode->hsync_len;\r
+       HDMIWrReg(VIDEO_EXT_HTOTAL_L, value & 0xFF);\r
+       HDMIWrReg(VIDEO_EXT_HTOTAL_H, (value >> 8) & 0xFF);\r
+       \r
+       value = mode->left_margin + mode->right_margin + mode->hsync_len;\r
+       HDMIWrReg(VIDEO_EXT_HBLANK_L, value & 0xFF);\r
+       HDMIWrReg(VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF);\r
+       \r
+       value = mode->left_margin + mode->hsync_len;\r
+       HDMIWrReg(VIDEO_EXT_HDELAY_L, value & 0xFF);\r
+       HDMIWrReg(VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF);\r
+       \r
+       value = mode->hsync_len;\r
+       HDMIWrReg(VIDEO_EXT_HDURATION_L, value & 0xFF);\r
+       HDMIWrReg(VIDEO_EXT_HDURATION_H, (value >> 8) & 0xFF);\r
+       \r
+       value = mode->upper_margin + mode->yres + mode->lower_margin + mode->vsync_len;\r
+       HDMIWrReg(VIDEO_EXT_VTOTAL_L, value & 0xFF);\r
+       HDMIWrReg(VIDEO_EXT_VTOTAL_H, (value >> 8) & 0xFF);\r
+       \r
+       value = mode->upper_margin + mode->vsync_len + mode->lower_margin;\r
+       HDMIWrReg(VIDEO_EXT_VBLANK, value & 0xFF);\r
+\r
+       if(vpara->vic == HDMI_720x480p_60Hz_4_3 || vpara->vic == HDMI_720x480p_60Hz_16_9)\r
+               value = 42;\r
+       else\r
+               value = mode->upper_margin + mode->vsync_len;\r
+\r
+       HDMIWrReg(VIDEO_EXT_VDELAY, value & 0xFF);\r
+       \r
+       value = mode->vsync_len;\r
+       HDMIWrReg(VIDEO_EXT_VDURATION, value & 0xFF);\r
+       #endif\r
+       \r
+       if(vpara->output_mode == OUTPUT_HDMI) {\r
+               rk610_hdmi_config_avi(vpara->vic, vpara->output_color);\r
+               hdmi_dbg(hdmi->dev, "[%s] sucess output HDMI.\n", __FUNCTION__);\r
+       }\r
+       else {\r
+               hdmi_dbg(hdmi->dev, "[%s] sucess output DVI.\n", __FUNCTION__); \r
+       }\r
+\r
+       // Power on TMDS\r
+       HDMIWrReg(PHY_PRE_EMPHASIS, v_PRE_EMPHASIS(0) | v_TMDS_PWRDOWN(0)); // TMDS power on\r
+       \r
+       // Enable TMDS\r
+       value = 0;\r
+       rk610_hdmi_i2c_read_reg(PHY_DRIVER, &value);\r
+       value |= v_TX_ENABLE(1);\r
+       HDMIWrReg(PHY_DRIVER, value);\r
+       \r
+       return 0;\r
+}\r
+\r
+static void rk610_hdmi_config_aai(void)\r
+{\r
+       int i;\r
+       char info[SIZE_AUDIO_INFOFRAME];\r
+       \r
+       memset(info, 0, SIZE_AUDIO_INFOFRAME);\r
+       \r
+       info[0] = 0x84;\r
+       info[1] = 0x01;\r
+       info[2] = 0x0A;\r
+       \r
+       info[3] = info[0] + info[1] + info[2];  \r
+       for (i = 4; i < SIZE_AUDIO_INFOFRAME; i++)\r
+       info[3] += info[i];\r
+       \r
+       info[3] = 0x100 - info[3];\r
+       \r
+       HDMIWrReg(CONTROL_PACKET_BUF_INDEX, INFOFRAME_AAI);\r
+       for(i = 0; i < SIZE_AUDIO_INFOFRAME; i++)\r
+               HDMIWrReg(CONTROL_PACKET_ADDR + i, info[i]);\r
+}\r
+\r
+int rk610_hdmi_sys_config_audio(struct hdmi_audio *audio)\r
+{\r
+       int rate, N, channel, mclk_fs;\r
+       \r
+       if(audio->channel < 3)\r
+               channel = I2S_CHANNEL_1_2;\r
+       else if(audio->channel < 5)\r
+               channel = I2S_CHANNEL_3_4;\r
+       else if(audio->channel < 7)\r
+               channel = I2S_CHANNEL_5_6;\r
+       else\r
+               channel = I2S_CHANNEL_7_8;\r
+               \r
+       switch(audio->rate)\r
+       {\r
+               case HDMI_AUDIO_FS_32000:\r
+                       rate = AUDIO_32K;\r
+                       N = N_32K;\r
+                       mclk_fs = MCLK_384FS;\r
+                       break;\r
+               case HDMI_AUDIO_FS_44100:\r
+                       rate = AUDIO_441K;\r
+                       N = N_441K;\r
+                       mclk_fs = MCLK_256FS;\r
+                       break;\r
+               case HDMI_AUDIO_FS_48000:\r
+                       rate = AUDIO_48K;\r
+                       N = N_48K;\r
+                       mclk_fs = MCLK_256FS;\r
+                       break;\r
+               case HDMI_AUDIO_FS_88200:\r
+                       rate = AUDIO_882K;\r
+                       N = N_882K;\r
+                       mclk_fs = MCLK_128FS;\r
+                       break;\r
+               case HDMI_AUDIO_FS_96000:\r
+                       rate = AUDIO_96K;\r
+                       N = N_96K;\r
+                       mclk_fs = MCLK_128FS;\r
+                       break;\r
+               case HDMI_AUDIO_FS_176400:\r
+                       rate = AUDIO_1764K;\r
+                       N = N_1764K;\r
+                       mclk_fs = MCLK_128FS;\r
+                       break;\r
+               case HDMI_AUDIO_FS_192000:\r
+                       rate = AUDIO_192K;\r
+                       N = N_192K;\r
+                       mclk_fs = MCLK_128FS;\r
+                       break;\r
+               default:\r
+                       dev_err(hdmi->dev, "[%s] not support such sample rate %d\n", __FUNCTION__, audio->rate);\r
+                       return -ENOENT;\r
+       }\r
+\r
+       //set_audio source I2S\r
+       HDMIWrReg(AUDIO_CTRL1, 0x00); //internal CTS, disable down sample, i2s input, disable MCLK\r
+       HDMIWrReg(AUDIO_SAMPLE_RATE, rate);\r
+       HDMIWrReg(AUDIO_I2S_MODE, v_I2S_MODE(I2S_STANDARD) | v_I2S_CHANNEL(channel) );  \r
+       HDMIWrReg(AUDIO_I2S_MAP, 0x00); \r
+       HDMIWrReg(AUDIO_I2S_SWAPS_SPDIF, 0); // no swap \r
+               \r
+    //Set N value\r
+    HDMIWrReg(AUDIO_N_H, (N >> 16) & 0x0F);\r
+    HDMIWrReg(AUDIO_N_M, (N >> 8) & 0xFF); \r
+       HDMIWrReg(AUDIO_N_L, N & 0xFF);    \r
+    rk610_hdmi_config_aai();\r
+    \r
+    return 0;\r
+}\r
+\r
+void rk610_hdmi_sys_enalbe_output(int enable)\r
+{\r
+       char mutestatus = 0;\r
+       \r
+       if(enable) {\r
+               rk610_hdmi_i2c_read_reg(AV_MUTE, &mutestatus);\r
+               if(mutestatus && (m_AUDIO_MUTE | m_VIDEO_BLACK)) {\r
+                       HDMIWrReg(AV_MUTE, v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));\r
+                       HDMIWrReg(SYS_CTRL, v_REG_CLK_SOURCE_IIS | v_PWR_ON | v_INT_POL_HIGH);\r
+                       HDMIWrReg(SYS_CTRL, v_REG_CLK_SOURCE_IIS | v_PWR_OFF | v_INT_POL_HIGH);\r
+                       HDMIWrReg(SYS_CTRL, v_REG_CLK_SOURCE_IIS | v_PWR_ON | v_INT_POL_HIGH);\r
+                       if(hdmi->hdcp_cb)\r
+                               hdmi->hdcp_cb();\r
+               }\r
+       }\r
+       else {\r
+               HDMIWrReg(AV_MUTE, v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1));          \r
+       }\r
+}\r
+\r
+int rk610_hdmi_sys_insert(void)\r
+{\r
+       hdmi_dbg(hdmi->dev, "%s \n", __FUNCTION__);\r
+       //Bring up analog module.\r
+       HDMIWrReg(PHY_BANDGAP_PWR, v_BANDGAP_PWR_UP);   //BG power on \r
+       HDMIWrReg(PHY_PLL_LDO_PWR, 0x00);               //PLL power on\r
+       msleep(1);\r
+       HDMIWrReg(PHY_PLL_CTRL, v_PLL_DISABLE(0));      //Analog reset\r
+       return 0;\r
+}\r
+\r
+int rk610_hdmi_sys_remove(void)\r
+{\r
+       hdmi_dbg(hdmi->dev, "%s \n", __FUNCTION__);\r
+       if(hdmi->hdcp_power_off_cb)\r
+               hdmi->hdcp_power_off_cb();\r
+       HDMIWrReg(PHY_DRIVER, v_MAIN_DRIVER(8)| v_PRE_DRIVER(0) | v_TX_ENABLE(0));\r
+       HDMIWrReg(PHY_PRE_EMPHASIS, v_PRE_EMPHASIS(0) | v_TMDS_PWRDOWN(1));     //Driver power down     \r
+       HDMIWrReg(PHY_PLL_CTRL, v_PLL_DISABLE(1) | v_PLL_RESET(1) | v_TMDS_RESET(1));\r
+       HDMIWrReg(PHY_PLL_LDO_PWR, v_LDO_PWR_DOWN(1));\r
+       HDMIWrReg(PHY_BANDGAP_PWR, v_BANDGAP_PWR_DOWN);\r
+       return 0;\r
+}
\ No newline at end of file
diff --git a/drivers/video/rockchip/hdmi/chips/rk610/rk610_hdmi_hw.h b/drivers/video/rockchip/hdmi/chips/rk610/rk610_hdmi_hw.h
new file mode 100755 (executable)
index 0000000..0e4cce9
--- /dev/null
@@ -0,0 +1,237 @@
+#ifndef _RK610_HDMI_HW_H
+#define _RK610_HDMI_HW_H
+
+enum {
+               OUTPUT_DVI = 0,
+               OUTPUT_HDMI
+       };
+       
+#define SYS_CTRL                                       0x00
+       #define m_INT_POL                               (1 << 0)
+       #define m_POWER                                 (1 << 1)
+       #define m_REG_CLK_SOURCE                (1 << 2)
+       #define v_INT_POL_HIGH                  1
+       #define v_INT_POL_LOW                   0
+       #define v_PWR_ON                                (0 << 1)
+       #define v_PWR_OFF                               (1 << 1)
+       #define v_REG_CLK_SOURCE_TMDS   (0 << 2)
+       #define v_REG_CLK_SOURCE_IIS    (1 << 2)
+#define VIDEO_CONTRL1                          0x01
+       #define m_VIDEO_INPUT_FORMAT    (7 << 1)
+       #define m_DE_SOURCE                             (1 << 0)
+       enum {
+               VIDEO_INPUT_SDR_RGB444 = 0,
+               VIDEO_INPUT_DDR_RGB444 = 5,
+               VIDEO_INPUT_DDR_YCBCR422 = 6                    
+       };
+       #define v_VIDEO_INPUT_FORMAT(n) (n << 1)
+       #define v_DE_EXTERNAL                   1
+       #define v_DE_INTERANL                   0
+       
+#define VIDEO_CONTRL2                          0x02
+       #define m_VIDEO_OUTPUT_FORMAT   (3 << 6)
+       #define m_VIDEO_INPUT_BITS              (3 << 4)
+       #define v_VIDEO_OUTPUT_FORMAT(n)(n << 6)
+       #define v_VIDEO_INPUT_BITS(n)   (n << 4)
+       enum{
+               VIDEO_INPUT_12BITS = 0,
+               VIDEO_INPUT_10BITS,
+               VIDEO_INPUT_8BITS
+       };
+#define VIDEO_CONTRL3                          0x04
+       #define m_SOF                                   (1 << 3)
+       #define m_CSC                                   (1 << 0)
+       #define v_SOF_ENABLE                    (0 << 3)
+       #define v_SOF_DISABLE                   (1 << 3)
+       #define v_CSC_ENABLE                    1
+       #define v_CSC_DISABLE                   0
+       
+#define AV_MUTE                                                0x05
+       #define m_AVMUTE_CLEAR                  (1 << 7)
+       #define m_AVMUTE_ENABLE                 (1 << 6)
+       #define m_AUDIO_MUTE                    (1 << 1)
+       #define m_VIDEO_BLACK                   (1 << 0)
+       #define v_AUDIO_MUTE(n)                 (n << 1)
+       #define v_VIDEO_MUTE(n)                 (n << 0)
+       
+#define VIDEO_TIMING_CTL                       0x08
+       #define v_HSYNC_POLARITY(n)             (n << 3)
+       #define v_VSYNC_POLARITY(n)             (n << 2)
+       #define v_INETLACE(n)                   (n << 1)
+       #define v_EXTERANL_VIDEO(n)             (n << 0)
+       
+#define VIDEO_EXT_HTOTAL_L                     0x09
+#define VIDEO_EXT_HTOTAL_H                     0x0a
+#define VIDEO_EXT_HBLANK_L                     0x0b
+#define VIDEO_EXT_HBLANK_H                     0x0c
+#define VIDEO_EXT_HDELAY_L                     0x0d
+#define VIDEO_EXT_HDELAY_H                     0x0e
+#define VIDEO_EXT_HDURATION_L          0x0f
+#define VIDEO_EXT_HDURATION_H          0x10
+#define VIDEO_EXT_VTOTAL_L                     0x11
+#define VIDEO_EXT_VTOTAL_H                     0x12
+#define VIDEO_EXT_VBLANK                       0x13
+#define VIDEO_EXT_VDELAY                       0x14
+#define VIDEO_EXT_VDURATION                    0x15
+
+#define AUDIO_CTRL1                                    0x35
+       enum {
+               CTS_SOURCE_INTERNAL = 0,
+               CTS_SOURCE_EXTERNAL
+       };
+       #define v_CTS_SOURCE(n)                 (n << 7)
+       enum {
+               DOWNSAMPLE_DISABLE = 0,
+               DOWNSAMPLE_1_2,
+               DOWNSAMPLE_1_4
+       };
+       #define v_DOWN_SAMPLE(n)                (n << 5)
+       enum {
+               AUDIO_SOURCE_IIS = 0,
+               AUDIO_SOURCE_SPDIF
+       };
+       #define v_AUDIO_SOURCE(n)               (n << 3)
+       #define v_MCLK_ENABLE(n)                (n << 2)
+       enum {
+               MCLK_128FS = 0,
+               MCLK_256FS,
+               MCLK_384FS,
+               MCLK_512FS
+       };
+       #define v_MCLK_RATIO(n)                 (n)
+       
+#define AUDIO_SAMPLE_RATE                      0x37
+       enum {
+               AUDIO_32K       = 0x3,
+               AUDIO_441K      = 0x0,
+               AUDIO_48K       = 0x2,
+               AUDIO_882K      = 0x8,
+               AUDIO_96K       = 0xa,
+               AUDIO_1764K     = 0xc,
+               AUDIO_192K      = 0xe,
+       };
+
+#define AUDIO_I2S_MODE                         0x38
+       enum {
+               I2S_CHANNEL_1_2 = 1,
+               I2S_CHANNEL_3_4 = 3,
+               I2S_CHANNEL_5_6 = 7,
+               I2S_CHANNEL_7_8 = 0xf
+       };
+       #define v_I2S_CHANNEL(n)                ((n) << 2)
+       enum {
+               I2S_STANDARD = 0,
+               I2S_LEFT_JUSTIFIED,
+               I2S_RIGHT_JUSTIFIED
+       };
+       #define v_I2S_MODE(n)                           (n)
+
+#define AUDIO_I2S_MAP                          0x39
+#define AUDIO_I2S_SWAPS_SPDIF          0x3a
+       #define v_SPIDF_FREQ(n)                 (n)     
+
+#define N_32K          0x1000
+#define N_441K                 0x1880
+#define N_882K                 0x3100
+#define N_1764K        0x6200
+#define N_48K          0x1800
+#define N_96K          0x3000
+#define N_192K                 0x6000
+
+#define AUDIO_N_H                                      0x3f
+#define AUDIO_N_M                                      0x40
+#define AUDIO_N_L                                      0x41
+
+#define AUDIO_CTS_H                                    0x45
+#define AUDIO_CTS_M                                    0x46
+#define AUDIO_CTS_L                                    0x47
+
+
+#define DDC_CLK_L                                      0x4b
+#define DDC_CLK_H                                      0x4c
+
+#define EDID_SEGMENT_POINTER   0x4d
+#define EDID_WORD_ADDR                 0x4e
+#define EDID_FIFO_OFFSET               0x4f
+#define EDID_FIFO_ADDR                 0x50
+
+/* CONTROL_PACKET_BUF_INDEX */
+#define CONTROL_PACKET_BUF_INDEX       0x9f
+enum {
+       INFOFRAME_AVI = 0x06,
+       INFOFRAME_AAI = 0x08
+};
+#define CONTROL_PACKET_ADDR                    0xa0
+
+
+#define SIZE_AVI_INFOFRAME                     0x11    // 14 bytes
+#define SIZE_AUDIO_INFOFRAME           0x0F    // 15 bytes
+enum {
+       AVI_COLOR_MODE_RGB = 0,
+       AVI_COLOR_MODE_YCBCR422,
+       AVI_COLOR_MODE_YCBCR444
+};
+enum {
+       AVI_COLORIMETRY_NO_DATA = 0,
+       AVI_COLORIMETRY_SMPTE_170M,
+       AVI_COLORIMETRY_ITU709,
+       AVI_COLORIMETRY_EXTENDED
+};
+enum {
+       AVI_CODED_FRAME_ASPECT_NO_DATA,
+       AVI_CODED_FRAME_ASPECT_4_3,
+       AVI_CODED_FRAME_ASPECT_16_9
+};
+enum {
+       ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME = 0x08,
+       ACTIVE_ASPECT_RATE_4_3,
+       ACTIVE_ASPECT_RATE_16_9,
+       ACTIVE_ASPECT_RATE_14_9
+};
+
+#define HDCP_CTRL                              0x52
+       #define m_HDMI_DVI                      (1 << 1)
+       #define v_HDMI_DVI(n)           (n << 1)
+
+#define INTERRUPT_MASK1                        0xc0
+#define INTERRUPT_STATUS1              0xc1
+       #define m_INT_HOTPLUG           (1 << 7)
+       #define m_INT_ACTIVE_VSYNC      (1 << 6)
+       #define m_INT_EDID_READY        (1 << 2)
+       
+#define INTERRUPT_MASK2                        0xc2
+#define INTERRUPT_STATUS2              0xc3
+       #define m_INT_HDCP_ERR          (1 << 7)
+       #define m_INT_BKSV_FLAG         (1 << 6)
+       #define m_INT_HDCP_OK           (1 << 4)
+
+#define HDMI_STATUS                            0xc8
+       #define m_HOTPLUG       (1 << 7)
+       #define m_DDC_SDA       (1 << 5)
+       #define m_DDC_SDC       (1 << 4)
+
+#define PHY_SYNC                               0xce            //sync phy parameter                            
+
+#define PHY_DRIVER                             0xe1
+       #define v_MAIN_DRIVER(n)        (n << 4)
+       #define v_PRE_DRIVER(n)         (n << 2)
+       #define v_TX_ENABLE(n)          (n << 1)
+       
+#define PHY_PRE_EMPHASIS               0xe2
+       #define v_PRE_EMPHASIS(n)       (n << 4)
+       #define v_TMDS_PWRDOWN(n)       (n)
+       
+#define PHY_PLL_TEST                   0xe3
+#define PHY_BANDGAP_PWR                        0xe4
+       #define v_BANDGAP_PWR_DOWN      0x03
+       #define v_BANDGAP_PWR_UP        0
+       
+#define PHY_PLL_CTRL                   0xe5
+       #define v_PLL_DISABLE(n)        (n << 4)
+       #define v_PLL_RESET(n)          (n << 3)
+       #define v_TMDS_RESET(n)         (n << 2)
+                       
+#define PHY_PLL_LDO_PWR                        0xe7
+       #define v_LDO_PWR_DOWN(n)       (n << 2)
+               
+#endif
\ No newline at end of file
index 7222a8cf33e2ccb1e07984c7e67f5c6236fc7053..5c4cf8ad48038d3a6fd48c5cadf9e0c0ab3b5016 100755 (executable)
@@ -30,12 +30,13 @@ enum {
 /* If HDMI_ENABLE, system will auto configure output mode according to EDID 
  * If HDMI_DISABLE, system will output mode according to macro HDMI_VIDEO_DEFAULT_MODE
  */
-#define HDMI_AUTO_CONFIGURE                    HDMI_ENABLE
+#define HDMI_AUTO_CONFIGURE                    HDMI_DISABLE
 
 /* default HDMI output audio mode */
 #define HDMI_AUDIO_DEFAULT_CHANNEL             2
 #define HDMI_AUDIO_DEFAULT_RATE                        HDMI_AUDIO_FS_44100
 #define HDMI_AUDIO_DEFAULT_WORD_LENGTH HDMI_AUDIO_WORD_LENGTH_16bit
+
 enum {
        VIDEO_INPUT_RGB_YCBCR_444 = 0,
        VIDEO_INPUT_YCBCR422,
@@ -45,11 +46,13 @@ enum {
        VIDEO_INPUT_RGB444_DDR,
        VIDEO_INPUT_YCBCR422_DDR
 };
+
 enum {
        VIDEO_OUTPUT_RGB444 = 0,
        VIDEO_OUTPUT_YCBCR444,
        VIDEO_OUTPUT_YCBCR422
 };
+
 enum {
        VIDEO_INPUT_COLOR_RGB = 0,
        VIDEO_INPUT_COLOR_YCBCR
index dc0c5d82fb4fe2411b63ce45709618d35416369e..14f7924d041c805ce92274d5113b6f5dbf79f920 100755 (executable)
@@ -33,13 +33,17 @@ static int hdmi_set_enable(struct rk_display_device *device, int enable)
        }
        
        if(enable == 0) {
-               disable_irq(hdmi->irq);
+               if(hdmi->irq)
+                       disable_irq(hdmi->irq);
                mutex_unlock(&hdmi->enable_mutex);
                hdmi->command = HDMI_CONFIG_ENABLE;
                queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, 0);
        }
        else {
-               enable_irq(hdmi->irq);
+               if(hdmi->irq)
+                       enable_irq(hdmi->irq);
+               else
+                       queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, 0);
                mutex_unlock(&hdmi->enable_mutex);
        }
        return 0;
index 5f34b23236dc6eed59978d1801cb6fac31af8cf5..3fe5274551f0b61049c74935774d2f1d074f8410 100755 (executable)
@@ -93,11 +93,11 @@ void hdmi_sys_remove(void)
 static void hdmi_sys_sleep(void)
 {
        mutex_lock(&hdmi->enable_mutex);
-       if(hdmi->enable)
+       if(hdmi->enable && hdmi->irq)
                disable_irq(hdmi->irq);                         
        hdmi->state = HDMI_SLEEP;
        hdmi->remove();
-       if(hdmi->enable)
+       if(hdmi->enable && hdmi->irq)
                enable_irq(hdmi->irq);
        mutex_unlock(&hdmi->enable_mutex);
 }