rk3036 hdmi: rk3036 hdmi driver independent from rk616
authorhjc <hjc@rock-chips.com>
Tue, 15 Jul 2014 11:03:02 +0000 (19:03 +0800)
committerhjc <hjc@rock-chips.com>
Wed, 16 Jul 2014 01:32:21 +0000 (09:32 +0800)
12 files changed:
drivers/video/rockchip/hdmi/chips/Kconfig
drivers/video/rockchip/hdmi/chips/Makefile
drivers/video/rockchip/hdmi/chips/rk3036/Kconfig [new file with mode: 0755]
drivers/video/rockchip/hdmi/chips/rk3036/Makefile [new file with mode: 0755]
drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdcp.c [new file with mode: 0755]
drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdcp.h [new file with mode: 0755]
drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdmi.c [new file with mode: 0755]
drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdmi.h [new file with mode: 0755]
drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdmi_hdcp.c [new file with mode: 0755]
drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdmi_hw.c [new file with mode: 0755]
drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdmi_hw.h [new file with mode: 0755]
drivers/video/rockchip/hdmi/rk_hdmi_lcdc.c

index 8f72dfed7b94c70bcc6afcd810fe8fbb69c6e648..93462410064a695b2bf5ffc550bd1bb36455a3b3 100755 (executable)
@@ -39,7 +39,7 @@ endif
 
 config  HDMI_RK616
         bool "RK616 HDMI support"
-#depends on MFD_RK616 || ARCH_RK3026
+depends on MFD_RK616 || ARCH_RK3026
                default y
         help
            Support rk616 hdmi if you say y here
@@ -48,6 +48,16 @@ if HDMI_RK616
 source "drivers/video/rockchip/hdmi/chips/rk616/Kconfig"
 endif
 
+config  HDMI_RK3036
+        bool "RK3036 HDMI support"
+               default y
+        help
+           Support rk3036 hdmi if you say y here
+
+if HDMI_RK3036
+source "drivers/video/rockchip/hdmi/chips/rk3036/Kconfig"
+endif
+
 choice
        prompt "HDMI Source LCDC select"
 config HDMI_SOURCE_LCDC0
index 0f2e4a1f146d5f9253cefa05e00fae44884ecc25..e61356c98eefe9cff3c9df0d79d3abbc0cb7bd09 100755 (executable)
@@ -9,4 +9,5 @@ obj-$(CONFIG_HDMI_RK2928) += rk2928/
 obj-$(CONFIG_HDMI_RK610) += rk610/
 obj-$(CONFIG_HDMI_CAT66121) += cat66121/
 obj-$(CONFIG_HDMI_RK616) += rk616/
+obj-$(CONFIG_HDMI_RK3036) += rk3036/
 obj-y += rk3288/
diff --git a/drivers/video/rockchip/hdmi/chips/rk3036/Kconfig b/drivers/video/rockchip/hdmi/chips/rk3036/Kconfig
new file mode 100755 (executable)
index 0000000..c60c1ff
--- /dev/null
@@ -0,0 +1,13 @@
+config HDCP_RK3036
+       bool "RK3036 HDCP support"
+        default n
+       help
+         HDCP Interface. This adds the High Definition Content Protection Interface.
+         See http://www.digital-cp.com/ for HDCP specification.
+
+config HDCP_RK3036_DEBUG
+       bool "RK3036 HDCP Debugging"
+        depends on HDCP_RK3036
+        default n
+       help
+         Enableds verbose debugging the the HDCP drivers
diff --git a/drivers/video/rockchip/hdmi/chips/rk3036/Makefile b/drivers/video/rockchip/hdmi/chips/rk3036/Makefile
new file mode 100755 (executable)
index 0000000..f6f27f9
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Makefile for HDMI linux kernel module.
+#
+
+ccflags-$(CONFIG_RK_HDMI_DEBUG) = -DDEBUG -DHDMI_DEBUG
+ccflags-$(CONFIG_HDCP_RK616_DEBUG) = -DHDCP_DEBUG
+
+obj-$(CONFIG_HDMI_RK3036) += rk3036_hdmi_hw.o rk3036_hdmi.o
+obj-$(CONFIG_HDCP_RK3036) += rk3036_hdmi_hdcp.o rk3036_hdcp.o
diff --git a/drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdcp.c b/drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdcp.c
new file mode 100755 (executable)
index 0000000..5d7d419
--- /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 "rk3036_hdmi.h"
+#include "rk3036_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;
+       }
+
+       rk3036_hdcp_disable();
+       rk3036_hdmi_control_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 = rk3036_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 = rk3036_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)
+{
+       rk3036_hdmi_control_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);
+       rk3036_hdcp_disable();
+       if(event == HDCP_DISABLE_CTL) {
+               hdcp->hdcp_state = HDCP_DISABLED;
+               if(hdcp->hdmi_state == HDMI_STARTED)
+                       rk3036_hdmi_control_output(true);
+       }
+       else if(event == HDCP_STOP_FRAME_EVENT)
+               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;
+       
+       rk3036_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 rk3036_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 rk3036_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;
+       }
+       
+       rk3036_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 rk3036_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(rk3036_hdcp_init);
+module_exit(rk3036_hdcp_exit);
diff --git a/drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdcp.h b/drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdcp.h
new file mode 100755 (executable)
index 0000000..c465f54
--- /dev/null
@@ -0,0 +1,190 @@
+#ifndef __RK3036_HDCP_H__
+#define __RK3036_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;
+
+#ifdef HDCP_DEBUG
+#define DBG(format, ...) \
+               printk(KERN_INFO "HDCP: " format "\n", ## __VA_ARGS__)
+#else
+#define DBG(format, ...)
+#endif
+
+extern void rk3036_hdcp_disable(void);
+extern int     rk3036_hdcp_start_authentication(void);
+extern int     rk3036_hdcp_check_bksv(void);
+extern int     rk3036_hdcp_load_key2mem(struct hdcp_keys *key);
+extern void rk3036_hdcp_interrupt(char *status1, char *status2);
+#endif /* __rk3036_HDCP_H__ */
diff --git a/drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdmi.c b/drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdmi.c
new file mode 100755 (executable)
index 0000000..f96bb0a
--- /dev/null
@@ -0,0 +1,483 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/uaccess.h>
+
+#include <linux/of_gpio.h>
+#include <linux/rk_fb.h>
+
+#if defined(CONFIG_DEBUG_FS)
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#endif
+
+#include "rk3036_hdmi.h"
+#include "rk3036_hdmi_hw.h"
+
+static struct rk_hdmi_device *hdmi_dev;
+
+#if defined(CONFIG_DEBUG_FS)
+static int rk3036_hdmi_reg_show(struct seq_file *s, void *v)
+{
+       int i = 0;
+       u32 val = 0;
+
+       seq_puts(s, "\n\n>>>rk3036_ctl reg");
+       for (i = 0; i < 16; i++)
+               seq_printf(s, " %2x", i);
+
+       seq_puts(s,
+                  "\n-----------------------------------------------------------------");
+
+       for (i = 0; i <= PHY_PRE_DIV_RATIO; i++) {
+               hdmi_readl(hdmi_dev, i, &val);
+               if (i % 16 == 0)
+                       seq_printf(s, "\n>>>rk3036_ctl %2x:", i);
+               seq_printf(s, " %02x", val);
+
+       }
+       seq_puts(s,
+                  "\n-----------------------------------------------------------------\n");
+
+       return 0;
+}
+
+static ssize_t rk3036_hdmi_reg_write(struct file *file, const char __user *buf,
+                                   size_t count, loff_t *ppos)
+{
+       u32 reg;
+       u32 val;
+       char kbuf[25];
+       struct hdmi *hdmi_drv = &hdmi_dev->driver;
+
+       if (copy_from_user(kbuf, buf, count))
+               return -EFAULT;
+       sscanf(kbuf, "%x%x", &reg, &val);
+       if ((reg < 0) || (reg > 0xed)) {
+               dev_info(hdmi_drv->dev, "it is no hdmi reg\n");
+               return count;
+       }
+       dev_info(hdmi_drv->dev, "/**********rk3036 reg config******/");
+       dev_info(hdmi_drv->dev, "\n reg=%x val=%x\n", reg, val);
+       hdmi_writel(hdmi_dev, reg, val);
+
+       return count;
+}
+
+static int rk3036_hdmi_reg_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, rk3036_hdmi_reg_show, NULL);
+}
+
+static const struct file_operations rk3036_hdmi_reg_fops = {
+       .owner = THIS_MODULE,
+       .open = rk3036_hdmi_reg_open,
+       .read = seq_read,
+       .write = rk3036_hdmi_reg_write,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+#endif
+
+static int rk3036_hdmi_clk_enable(struct rk_hdmi_device *hdmi_dev)
+{
+       if (!hdmi_dev->clk_on) {
+               clk_prepare_enable(hdmi_dev->hclk);
+               spin_lock(&hdmi_dev->reg_lock);
+               hdmi_dev->clk_on = 1;
+               spin_unlock(&hdmi_dev->reg_lock);
+       }
+
+       return 0;
+}
+
+static int rk3036_hdmi_clk_disable(struct rk_hdmi_device *hdmi_dev)
+{
+       if (!hdmi_dev->clk_on) {
+               spin_lock(&hdmi_dev->reg_lock);
+               hdmi_dev->clk_on = 0;
+               spin_unlock(&hdmi_dev->reg_lock);
+               clk_disable_unprepare(hdmi_dev->hclk);
+       }
+
+       return 0;
+}
+
+int rk3036_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))
+{
+       struct hdmi *hdmi_drv = &hdmi_dev->driver;
+
+       if (hdmi_drv == NULL)
+               return HDMI_ERROR_FALSE;
+
+       hdmi_drv->hdcp_cb = hdcp_cb;
+       hdmi_drv->hdcp_irq_cb = hdcp_irq_cb;
+       hdmi_drv->hdcp_power_on_cb = hdcp_power_on_cb;
+       hdmi_drv->hdcp_power_off_cb = hdcp_power_off_cb;
+
+       return HDMI_ERROR_SUCESS;
+}
+
+static void rk3036_hdmi_early_suspend(void)
+{
+       struct hdmi *hdmi_drv = &hdmi_dev->driver;
+
+       hdmi_dbg(hdmi_drv->dev, "hdmi enter early suspend pwr %d state %d\n",
+                hdmi_drv->pwr_mode, hdmi_drv->state);
+
+       flush_delayed_work(&hdmi_drv->delay_work);
+       mutex_lock(&hdmi_drv->enable_mutex);
+       hdmi_drv->suspend = 1;
+       if (!hdmi_drv->enable) {
+               mutex_unlock(&hdmi_drv->enable_mutex);
+               return;
+       }
+
+       if (hdmi_drv->irq)
+               disable_irq(hdmi_drv->irq);
+
+       mutex_unlock(&hdmi_drv->enable_mutex);
+       hdmi_drv->command = HDMI_CONFIG_ENABLE;
+       init_completion(&hdmi_drv->complete);
+       hdmi_drv->wait = 1;
+       queue_delayed_work(hdmi_drv->workqueue, &hdmi_drv->delay_work, 0);
+       wait_for_completion_interruptible_timeout(&hdmi_drv->complete,
+                                                 msecs_to_jiffies(5000));
+       flush_delayed_work(&hdmi_drv->delay_work);
+
+}
+
+static void rk3036_hdmi_early_resume(void)
+{
+       struct hdmi *hdmi_drv = &hdmi_dev->driver;
+
+       hdmi_dbg(hdmi_drv->dev, "hdmi exit early resume\n");
+
+       mutex_lock(&hdmi_drv->enable_mutex);
+
+       hdmi_drv->suspend = 0;
+       rk3036_hdmi_initial(hdmi_drv);
+       if (hdmi_drv->enable && hdmi_drv->irq) {
+               enable_irq(hdmi_drv->irq);
+               rk3036_hdmi_irq(hdmi_drv);
+       }
+
+       queue_delayed_work(hdmi_drv->workqueue, &hdmi_drv->delay_work,
+                          msecs_to_jiffies(10));
+       mutex_unlock(&hdmi_drv->enable_mutex);
+}
+
+static int rk3036_hdmi_fb_event_notify(struct notifier_block *self,
+                                     unsigned long action, void *data)
+{
+       struct fb_event *event = data;
+       int blank_mode = *((int *)event->data);
+
+       if (action == FB_EARLY_EVENT_BLANK) {
+               switch (blank_mode) {
+               case FB_BLANK_UNBLANK:
+                       break;
+               default:
+                       rk3036_hdmi_early_suspend();
+                       break;
+               }
+       } else if (action == FB_EVENT_BLANK) {
+               switch (blank_mode) {
+               case FB_BLANK_UNBLANK:
+                       rk3036_hdmi_early_resume();
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block rk3036_hdmi_fb_notifier = {
+       .notifier_call = rk3036_hdmi_fb_event_notify,
+};
+
+
+static void rk3036_delay_work_func(struct work_struct *work)
+{
+       struct hdmi *hdmi_drv = &hdmi_dev->driver;
+
+       if (hdmi_drv->suspend == 0) {
+               if (hdmi_drv->enable == 1)
+                       rk3036_hdmi_irq(hdmi_drv);
+               if (hdmi_drv->irq == 0)
+                       queue_delayed_work(hdmi_drv->workqueue, &hdmi_dev->rk3036_delay_work,
+                               msecs_to_jiffies(100));                 
+       }
+}
+
+static irqreturn_t rk3036_hdmi_irq_func(int irq, void *dev_id)
+{
+       struct hdmi *hdmi_drv = &hdmi_dev->driver;
+       if ((hdmi_drv->suspend == 0) && (hdmi_drv->enable == 1)) {
+               hdmi_dbg(hdmi_drv->dev,
+                        "line = %d, rk3036_hdmi_irq_func irq triggered.\n",
+                        __LINE__);
+               rk3036_hdmi_irq(hdmi_drv);
+       }
+       
+       return IRQ_HANDLED;
+}
+
+static int rk3036_hdmi_drv_init(struct hdmi *hdmi_drv)
+{
+       int ret = 0;
+       int lcdc_id = 0;
+       struct rk_screen screen;
+
+       rk_fb_get_prmry_screen(&screen);
+
+       /* hdmi is extend as default,TODO modify if hdmi is primary */
+       /*lcdc_id = (screen.lcdc_id == 0) ? 1 : 0;*/
+       lcdc_id = screen.lcdc_id;//for box,hdmi is primary
+       
+       if (lcdc_id == 0)
+               hdmi_drv->lcdc = rk_get_lcdc_drv("lcdc0");
+       else
+               hdmi_drv->lcdc = rk_get_lcdc_drv("lcdc1");
+
+       if (IS_ERR(hdmi_drv->lcdc)) {
+               dev_err(hdmi_drv->dev,
+                       "can not connect to video source lcdc\n");
+               ret = -ENXIO;
+               return ret;
+       }
+
+       hdmi_drv->xscale = 100;
+       hdmi_drv->yscale = 100;
+
+       /*spin_lock_init(&hdmi_drv->irq_lock);*/
+       mutex_init(&hdmi_drv->enable_mutex);
+       hdmi_sys_init(hdmi_drv);
+       ret = rk3036_hdmi_initial(hdmi_drv);
+
+       return ret;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id rk3036_hdmi_of_match[] = {
+       {.compatible = "rockchip,rk3036-hdmi",},
+       {}
+};
+
+MODULE_DEVICE_TABLE(of, rk3036_hdmi_of_match);
+#endif
+
+static int rk3036_hdmi_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct hdmi *hdmi_drv;
+       struct resource *res;
+
+       hdmi_dev = devm_kzalloc(&pdev->dev, sizeof(struct rk_hdmi_device),
+                               GFP_KERNEL);
+       if (!hdmi_dev) {
+               dev_err(&pdev->dev, ">>rk3036_hdmi kmalloc fail!");
+               return -ENOMEM;
+       }
+
+       hdmi_drv = &hdmi_dev->driver;
+       hdmi_drv->dev = &pdev->dev;
+       platform_set_drvdata(pdev, hdmi_dev);
+       spin_lock_init(&hdmi_dev->reg_lock);
+
+#ifdef CONFIG_SWITCH
+       hdmi_drv->switch_hdmi.name = "hdmi";
+       switch_dev_register(&(hdmi_drv->switch_hdmi));
+#endif
+       hdmi_register_display_sysfs(hdmi_drv, NULL);
+       fb_register_client(&rk3036_hdmi_fb_notifier);
+
+       hdmi_drv->workqueue = create_singlethread_workqueue("hdmi");
+       INIT_DELAYED_WORK(&(hdmi_drv->delay_work), hdmi_work);
+       INIT_DELAYED_WORK(&hdmi_dev->rk3036_delay_work, rk3036_delay_work_func);
+
+       /* enable clk */
+       hdmi_dev->hclk = devm_clk_get(hdmi_drv->dev, "pclk_hdmi");
+       if (IS_ERR(hdmi_dev->hclk)) {
+               dev_err(hdmi_drv->dev, "Unable to get hdmi hclk\n");
+               ret = -ENXIO;
+               goto err1;
+       }
+       rk3036_hdmi_clk_enable(hdmi_dev);       /* enable clk may move to irq func */
+       hdmi_dev->hclk_rate = clk_get_rate(hdmi_dev->hclk);
+       /* request and remap iomem */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(hdmi_drv->dev, "Unable to get register resource\n");
+               ret = -ENXIO;
+               goto err2;
+       }
+       hdmi_dev->regbase_phy = res->start;
+       hdmi_dev->regsize_phy = resource_size(res);
+       hdmi_dev->regbase = devm_ioremap_resource(hdmi_drv->dev, res);
+       if (IS_ERR(hdmi_dev->regbase)) {
+               ret = PTR_ERR(hdmi_dev->regbase);
+               dev_err(hdmi_drv->dev, "cannot ioremap registers,err=%d\n",
+                       ret);
+               goto err2;
+       }
+       if (rk3036_hdmi_drv_init(hdmi_drv))
+               goto err0;
+
+       /* get the IRQ */
+       hdmi_drv->irq = platform_get_irq(pdev, 0);
+       if (hdmi_drv->irq <= 0) {
+               dev_err(hdmi_drv->dev, "failed to get hdmi irq resource (%d).\n",
+                       hdmi_drv->irq);
+               hdmi_drv->irq = 0;
+       } else {
+               /* request the IRQ */
+               ret = devm_request_irq(hdmi_drv->dev, hdmi_drv->irq,
+                                      rk3036_hdmi_irq_func, 0,
+                                      dev_name(hdmi_drv->dev), hdmi_drv);
+               if (ret) {
+                       dev_err(hdmi_drv->dev, "hdmi request_irq failed (%d)\n",
+                               ret);
+                       goto err2;
+               }
+       }
+
+#if defined(CONFIG_DEBUG_FS)
+       hdmi_dev->debugfs_dir = debugfs_create_dir("rk3036", NULL);
+       if (IS_ERR(hdmi_dev->debugfs_dir)) {
+               dev_err(hdmi_drv->dev,
+                       "failed to create debugfs dir for rk3036!\n");
+       } else {
+               debugfs_create_file("hdmi", S_IRUSR,
+                                   hdmi_dev->debugfs_dir, hdmi_drv,
+                                   &rk3036_hdmi_reg_fops);
+       }
+       
+#endif
+
+       queue_delayed_work(hdmi_drv->workqueue, &hdmi_dev->rk3036_delay_work,
+                          msecs_to_jiffies(0));
+       dev_info(hdmi_drv->dev, "rk3036 hdmi probe success.\n");
+
+       return 0;
+
+err2:
+       rk3036_hdmi_clk_disable(hdmi_dev);
+err1:
+       fb_unregister_client(&rk3036_hdmi_fb_notifier);
+       hdmi_unregister_display_sysfs(hdmi_drv);
+#ifdef CONFIG_SWITCH
+       switch_dev_unregister(&(hdmi_drv->switch_hdmi));
+#endif
+
+err0:
+       hdmi_dbg(hdmi_drv->dev, "rk3036 hdmi probe error.\n");
+       kfree(hdmi_dev);
+       hdmi_dev = NULL;
+       return ret;
+}
+
+static int rk3036_hdmi_remove(struct platform_device *pdev)
+{
+       struct rk_hdmi_device *hdmi_dev = platform_get_drvdata(pdev);
+       struct hdmi *hdmi_drv = NULL;
+
+       if (hdmi_dev) {
+               hdmi_drv = &hdmi_dev->driver;
+               mutex_lock(&hdmi_drv->enable_mutex);
+               if (!hdmi_drv->suspend && hdmi_drv->enable && hdmi_drv->irq)
+                       disable_irq(hdmi_drv->irq);
+               mutex_unlock(&hdmi_drv->enable_mutex);
+               if (hdmi_drv->irq)
+                       free_irq(hdmi_drv->irq, NULL);
+
+               flush_workqueue(hdmi_drv->workqueue);
+               destroy_workqueue(hdmi_drv->workqueue);
+#ifdef CONFIG_SWITCH
+               switch_dev_unregister(&(hdmi_drv->switch_hdmi));
+#endif
+               hdmi_unregister_display_sysfs(hdmi_drv);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+               unregister_early_suspend(&hdmi_drv->early_suspend);
+#endif
+               fb_destroy_modelist(&hdmi_drv->edid.modelist);
+               if (hdmi_drv->edid.audio)
+                       kfree(hdmi_drv->edid.audio);
+               if (hdmi_drv->edid.specs) {
+                       if (hdmi_drv->edid.specs->modedb)
+                               kfree(hdmi_drv->edid.specs->modedb);
+                       kfree(hdmi_drv->edid.specs);
+               }
+
+               hdmi_dbg(hdmi_drv->dev, "rk3036 hdmi removed.\n");
+               kfree(hdmi_dev);
+               hdmi_dev = NULL;
+       }
+
+       return 0;
+}
+
+static void rk3036_hdmi_shutdown(struct platform_device *pdev)
+{
+       struct rk_hdmi_device *hdmi_dev = platform_get_drvdata(pdev);
+       struct hdmi *hdmi_drv = NULL;
+
+       if (hdmi_dev) {
+               hdmi_drv = &hdmi_dev->driver;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+               unregister_early_suspend(&hdmi_drv->early_suspend);
+#endif
+               flush_delayed_work(&hdmi_drv->delay_work);
+               mutex_lock(&hdmi_drv->enable_mutex);
+               hdmi_drv->suspend = 1;
+               if (!hdmi_drv->enable) {
+                       mutex_unlock(&hdmi_drv->enable_mutex);
+                       return;
+               }
+               if (hdmi_drv->irq)
+                       disable_irq(hdmi_drv->irq);
+               mutex_unlock(&hdmi_drv->enable_mutex);
+       }
+       hdmi_dbg(hdmi_drv->dev, "rk3036 hdmi shut down.\n");
+}
+
+
+static struct platform_driver rk3036_hdmi_driver = {
+       .probe = rk3036_hdmi_probe,
+       .remove = rk3036_hdmi_remove,
+       .driver = {
+                  .name = "rk3036-hdmi",
+                  .owner = THIS_MODULE,
+                  .of_match_table = of_match_ptr(rk3036_hdmi_of_match),                   
+                  },
+       .shutdown = rk3036_hdmi_shutdown,
+};
+
+static int __init rk3036_hdmi_init(void)
+{
+       return platform_driver_register(&rk3036_hdmi_driver);
+}
+
+static void __exit rk3036_hdmi_exit(void)
+{
+       platform_driver_unregister(&rk3036_hdmi_driver);
+}
+
+late_initcall(rk3036_hdmi_init);
+module_exit(rk3036_hdmi_exit);
diff --git a/drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdmi.h b/drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdmi.h
new file mode 100755 (executable)
index 0000000..afdec40
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __RK3036_HDMI_H__
+#define __RK3036_HDMI_H__
+
+#include "../../rk_hdmi.h"
+
+enum {
+       INPUT_IIS,
+       INPUT_SPDIF
+};
+
+#if defined(CONFIG_SND_RK_SOC_HDMI_SPDIF)
+#define HDMI_CODEC_SOURCE_SELECT INPUT_SPDIF
+#else
+#define HDMI_CODEC_SOURCE_SELECT INPUT_IIS
+#endif
+
+extern void rk3036_hdmi_control_output(struct hdmi *hdmi, int enable);
+extern int rk3036_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));
+
+struct rk_hdmi_device {
+       int clk_on;
+       spinlock_t reg_lock;
+       struct hdmi driver;
+       void __iomem *regbase;
+       int regbase_phy;
+       int regsize_phy;
+       struct clk *pd;
+       struct clk *hclk;       /* HDMI AHP clk */
+       struct delayed_work rk3036_delay_work;
+       struct work_struct rk3036_irq_work_struct;
+       struct dentry *debugfs_dir;
+       unsigned int hclk_rate;
+};
+
+#endif /* __RK3036_HDMI_H__ */
diff --git a/drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdmi_hdcp.c b/drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdmi_hdcp.c
new file mode 100755 (executable)
index 0000000..1177f94
--- /dev/null
@@ -0,0 +1,143 @@
+#include <linux/delay.h>
+#include "rk3036_hdmi.h"
+#include "rk3036_hdmi_hw.h"
+#include "rk3036_hdcp.h"
+
+#define HDCPWrReg      HDMIWrReg
+#define HDCPRdReg      HDMIRdReg
+#define HDCPMskReg(temp,addr,Msk,val)  do{ \
+                                               HDMIRdReg(addr,&temp); \
+                                               HDMIWrReg(addr, ((val)&(Msk))|(temp&(~Msk))); \
+                                       }while(0)
+       
+void rk3036_hdcp_disable(void)
+{
+       char temp;
+       
+       // Diable HDCP Interrupt
+       HDCPWrReg(HDCP_INT_MASK1, 0x00);
+       // Stop and Reset HDCP
+       HDCPMskReg(temp, HDCP_CTRL1, m_ENCRYPT_ENABLE | m_AUTH_STOP | m_HDCP_RESET, 
+               v_ENCRYPT_ENABLE(0) | v_AUTH_STOP(1) | v_HDCP_RESET(1) );
+}
+
+int    rk3036_hdcp_load_key2mem(struct hdcp_keys *key)
+{
+       int i;
+       DBG("HDCP: rk3036_hdcp_load_key2mem start");
+       // Write 40 private key
+       for(i = 0; i < HDCP_PRIVATE_KEY_SIZE; i++)
+               HDCPWrReg(HDCP_KEY_FIFO, key->DeviceKey[i]);
+       
+       // Write 1st aksv
+       for(i = 0; i < 5; i++)
+               HDCPWrReg(HDCP_KEY_FIFO, key->KSV[i]);
+               
+       // Write 2nd aksv
+       for(i = 0; i < 5; i++)
+               HDCPWrReg(HDCP_KEY_FIFO, key->KSV[i]);
+       DBG("HDCP: rk3036_hdcp_load_key2mem end");
+       return HDCP_OK;
+}
+
+int    rk3036_hdcp_start_authentication(void)
+{
+       char temp;
+       int retry = 0;
+
+       if(hdcp->keys == NULL) {
+               printk(KERN_ERR "HDCP: key is not loaded\n");
+               return HDCP_KEY_ERR;
+       }
+       
+       // Select TMDS CLK to configure regs
+       HDCPMskReg(temp, SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_TMDS);
+       
+       HDCPRdReg(HDCP_KEY_STATUS,&temp);
+       while( ( temp & m_KEY_READY) == 0 ) {
+               if(retry > 10) {
+                       printk(KERN_ERR "HDCP: loaded key error\n");
+                       return HDCP_KEY_ERR;
+               }
+               rk3036_hdcp_load_key2mem(hdcp->keys);
+               msleep(1);
+               HDCPRdReg(HDCP_KEY_STATUS,&temp);
+       }
+       
+       // Config DDC bus clock: ddc_clk = reg_clk/4*(reg 0x4c 0x4b)
+       DBG("TMDS frequency %d", hdmi->tmdsclk);
+       retry = hdmi->tmdsclk/(HDCP_DDC_CLK*4);
+       HDCPWrReg(DDC_CLK_L, retry & 0xFF);
+       HDCPWrReg(DDC_CLK_H, (retry >> 8) & 0xFF);
+       
+       HDCPWrReg(HDCP_CTRL2, 0x00);
+       
+       //Enable interrupt
+       HDCPWrReg(HDCP_INT_MASK1, m_INT_HDCP_ERR | m_INT_BKSV_READY | m_INT_BKSV_UPDATE | m_INT_AUTH_SUCCESS | m_INT_AUTH_READY);
+//     HDCPWrReg(HDCP_INT_MASK2, 0xFF);
+       //Start authentication
+       HDCPMskReg(temp, HDCP_CTRL1, m_AUTH_START | m_ENCRYPT_ENABLE | m_ADVANED_ENABLE, v_AUTH_START(1) | v_ENCRYPT_ENABLE(1) | v_ADVANED_ENABLE(0));
+       
+       return HDCP_OK;
+}
+
+int    rk3036_hdcp_check_bksv(void)
+{
+       int i, j;
+       char temp = 0, bksv[5];
+       char *invalidkey;
+       
+       for(i = 0; i < 5; i++) {
+               HDCPRdReg(HDCP_KSV_BYTE0 + (4 - i),&temp);
+               bksv[i] = temp & 0xFF;
+       }
+       DBG("bksv is 0x%02x%02x%02x%02x%02x", bksv[0], bksv[1], bksv[2], bksv[3], bksv[4]);
+       
+       temp = 0;       
+       for (i = 0; i < 5; i++)
+       {
+       for (j = 0; j < 8; j++)
+       {
+               if (bksv[i] & 0x01)
+               {
+                       temp++;
+               }
+               bksv[i] >>= 1;
+       }
+       }
+       if (temp != 20)
+       return HDCP_KSV_ERR;
+       
+       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");
+                       HDCPMskReg(temp, HDCP_CTRL1, m_BKSV_INVALID | m_ENCRYPT_ENABLE, v_BKSV_INVALID(1) | v_ENCRYPT_ENABLE(1));
+                       return HDCP_KSV_ERR;
+               }
+       }
+       HDCPMskReg(temp, HDCP_CTRL1, m_BKSV_VALID | m_ENCRYPT_ENABLE, v_BKSV_VALID(1) | v_ENCRYPT_ENABLE(1));
+       return HDCP_OK;
+}
+
+void rk3036_hdcp_interrupt(char *status1, char *status2)
+{
+       char interrupt1 = 0;
+       char interrupt2 = 0;
+       char temp =0;
+       HDCPRdReg(HDCP_INT_STATUS1,&interrupt1);
+       HDCPRdReg(HDCP_INT_STATUS2,&interrupt2);
+       if(interrupt1) {
+               HDCPWrReg(HDCP_INT_STATUS1, interrupt1);
+               if(interrupt1 & m_INT_HDCP_ERR){
+                       HDCPRdReg(HDCP_ERROR,&temp);
+                       printk(KERN_INFO "HDCP: Error 0x%02x\n", temp);
+               }
+       }
+       if(interrupt2)
+               HDCPWrReg(HDCP_INT_STATUS2, interrupt2);
+       
+       *status1 = interrupt1;
+       *status2 = interrupt2;
+}
diff --git a/drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdmi_hw.c b/drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdmi_hw.c
new file mode 100755 (executable)
index 0000000..5ea3436
--- /dev/null
@@ -0,0 +1,573 @@
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/of_irq.h>
+#include "rk3036_hdmi.h"
+#include "rk3036_hdmi_hw.h"
+
+static int __maybe_unused rk3036_hdmi_show_reg(struct hdmi *hdmi_drv)
+{
+       int i = 0;
+       u32 val = 0;
+       struct rk_hdmi_device *hdmi_dev = container_of(hdmi_drv,
+                                                      struct rk_hdmi_device,
+                                                      driver);
+
+       printk("\n>>>rk3036_ctl reg");
+       for (i = 0; i < 16; i++)
+               printk(" %2x", i);
+
+       printk("\n-----------------------------------------------------------------");
+
+       for (i = 0; i <= PHY_PRE_DIV_RATIO; i++) {
+               hdmi_readl(hdmi_dev, i, &val);
+               if (i % 16 == 0)
+                       printk("\n>>>rk3036_ctl %2x:", i);
+               printk(" %02x", val);
+       }
+       printk("\n-----------------------------------------------------------------\n");
+
+       return 0;
+}
+
+static inline void delay100us(void)
+{
+       msleep(1);
+}
+
+static void rk3036_hdmi_av_mute(struct hdmi *hdmi_drv, bool enable)
+{
+       struct rk_hdmi_device *hdmi_dev = container_of(hdmi_drv,
+                                                      struct rk_hdmi_device,
+                                                      driver);
+
+       hdmi_writel(hdmi_dev, AV_MUTE,
+                   v_AUDIO_MUTE(enable) | v_VIDEO_MUTE(enable));
+}
+
+static void rk3036_hdmi_sys_power(struct hdmi *hdmi_drv, bool enable)
+{
+       struct rk_hdmi_device *hdmi_dev = container_of(hdmi_drv,
+                                                      struct rk_hdmi_device,
+                                                      driver);
+
+       if (enable)
+               hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_POWER, v_PWR_ON);
+       else
+               hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_POWER, v_PWR_OFF);
+}
+
+static void rk3036_hdmi_set_pwr_mode(struct hdmi *hdmi_drv, int mode)
+{
+       struct rk_hdmi_device *hdmi_dev = container_of(hdmi_drv,
+                                                      struct rk_hdmi_device,
+                                                      driver);
+
+       if (hdmi_drv->pwr_mode == mode)
+               return;
+
+       hdmi_dbg(hdmi_drv->dev, "%s change pwr_mode %d --> %d\n", __func__,
+                hdmi_drv->pwr_mode, mode);
+
+       switch (mode) {
+       case NORMAL:
+               hdmi_dbg(hdmi_drv->dev,
+                        "%s change pwr_mode NORMAL pwr_mode = %d, mode = %d\n",
+                        __func__, hdmi_drv->pwr_mode, mode);
+               rk3036_hdmi_sys_power(hdmi_drv, false);
+               hdmi_writel(hdmi_dev, PHY_DRIVER, 0x99);
+               hdmi_writel(hdmi_dev, PHY_PRE_EMPHASIS, 0x0f);
+               hdmi_writel(hdmi_dev, PHY_SYS_CTL, 0x15);
+               hdmi_writel(hdmi_dev, PHY_SYS_CTL, 0x14);
+               hdmi_writel(hdmi_dev, PHY_SYS_CTL, 0x10);
+               hdmi_writel(hdmi_dev, PHY_CHG_PWR, 0x0f);
+               hdmi_writel(hdmi_dev, 0xce, 0x00);
+               hdmi_writel(hdmi_dev, 0xce, 0x01);
+               rk3036_hdmi_av_mute(hdmi_drv, 1);
+               rk3036_hdmi_sys_power(hdmi_drv, true);
+               break;
+       case LOWER_PWR:
+               hdmi_dbg(hdmi_drv->dev,
+                        "%s change pwr_mode LOWER_PWR pwr_mode = %d, mode = %d\n",
+                        __func__, hdmi_drv->pwr_mode, mode);
+               rk3036_hdmi_av_mute(hdmi_drv, 0);
+               rk3036_hdmi_sys_power(hdmi_drv, false);
+               hdmi_writel(hdmi_dev, PHY_DRIVER, 0x00);
+               hdmi_writel(hdmi_dev, PHY_PRE_EMPHASIS, 0x00);
+               hdmi_writel(hdmi_dev, PHY_CHG_PWR, 0x00);
+               hdmi_writel(hdmi_dev, PHY_SYS_CTL, 0x17);
+               break;
+       default:
+               hdmi_dbg(hdmi_drv->dev, "unkown rk3036 hdmi pwr mode %d\n",
+                        mode);
+       }
+
+       hdmi_drv->pwr_mode = mode;
+}
+
+int rk3036_hdmi_detect_hotplug(struct hdmi *hdmi_drv)
+{
+       int value = 0;
+       struct rk_hdmi_device *hdmi_dev = container_of(hdmi_drv,
+                                                      struct rk_hdmi_device,
+                                                      driver);
+
+       hdmi_dbg(hdmi_drv->dev, "[%s] value %02x\n", __func__, value);
+       hdmi_readl(hdmi_dev, HDMI_STATUS, &value);
+       value &= m_HOTPLUG;
+       if (value == m_HOTPLUG)
+               return HDMI_HPD_ACTIVED;
+       else if (value)
+               return HDMI_HPD_INSERT;
+       else
+               return HDMI_HPD_REMOVED;
+}
+int rk3036_hdmi_insert(struct hdmi *hdmi_drv)
+{
+       rk3036_hdmi_set_pwr_mode(hdmi_drv, NORMAL);
+       return 0;
+}
+
+
+int rk3036_hdmi_read_edid(struct hdmi *hdmi_drv, int block, u8 *buf)
+{
+       u32 c = 0;
+       u8 segment = 0;
+       u8 offset = 0;
+       int ret = -1;
+       int i, j;
+       int ddc_bus_freq;
+       int trytime;
+       int checksum = 0;
+       struct rk_hdmi_device *hdmi_dev = container_of(hdmi_drv,
+                                                      struct rk_hdmi_device,
+                                                      driver);
+       if (block % 2)
+               offset = HDMI_EDID_BLOCK_SIZE;
+
+       if (block / 2)
+               segment = 1;
+       ddc_bus_freq = (hdmi_dev->hclk_rate >> 2) / HDMI_SCL_RATE;
+       hdmi_writel(hdmi_dev, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF);
+       hdmi_writel(hdmi_dev, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF);
+
+       hdmi_dbg(hdmi_drv->dev,
+                "EDID DATA (Segment = %d Block = %d Offset = %d):\n",
+                (int)segment, (int)block, (int)offset);
+       disable_irq(hdmi_drv->irq);
+
+       /* Enable edid interrupt */
+       hdmi_writel(hdmi_dev, INTERRUPT_MASK1, m_INT_EDID_READY);
+
+       for (trytime = 0; trytime < 10; trytime++) {
+               checksum = 0;
+               hdmi_writel(hdmi_dev, INTERRUPT_STATUS1, 0x04);
+
+               /* Set edid fifo first addr */
+               hdmi_writel(hdmi_dev, EDID_FIFO_OFFSET, 0x00);
+
+               /* Set edid word address 0x00/0x80 */
+               hdmi_writel(hdmi_dev, EDID_WORD_ADDR, offset);
+
+               /* Set edid segment pointer */
+               hdmi_writel(hdmi_dev, EDID_SEGMENT_POINTER, segment);
+
+               for (i = 0; i < 10; i++) {
+                       /* Wait edid interrupt */
+                       msleep(10);
+                       c = 0x00;
+                       hdmi_readl(hdmi_dev, INTERRUPT_STATUS1, &c);
+
+                       if (c & m_INT_EDID_READY)
+                               break;
+               }
+
+               if (c & m_INT_EDID_READY) {
+                       for (j = 0; j < HDMI_EDID_BLOCK_SIZE; j++) {
+                               c = 0;
+                               hdmi_readl(hdmi_dev, 0x50, &c);
+                               buf[j] = c;
+                               checksum += c;
+#ifdef HDMI_DEBUG
+                               if (j % 16 == 0)
+                                       printk("\n>>>0x%02x: ",j);
+
+                               printk("0x%02x ", c);
+#endif
+                       }
+
+                       /* clear EDID interrupt reg */
+                       hdmi_writel(hdmi_dev, INTERRUPT_STATUS1,
+                                   m_INT_EDID_READY);
+
+                       if ((checksum & 0xff) == 0) {
+                               ret = 0;
+                               hdmi_dbg(hdmi_drv->dev,
+                                        "[%s] edid read sucess\n", __func__);
+                               break;
+                       }
+               }
+       }
+       /*close edid irq*/
+       hdmi_writel(hdmi_dev, INTERRUPT_MASK1, 0);
+       enable_irq(hdmi_drv->irq);
+
+       return ret;
+}
+
+static void rk3036_hdmi_config_avi(struct hdmi *hdmi_drv,
+                                       unsigned char vic, unsigned char output_color)
+{
+       int i;
+       char info[SIZE_AVI_INFOFRAME];
+       struct rk_hdmi_device *hdmi_dev = container_of(hdmi_drv,
+                                                      struct rk_hdmi_device,
+                                                      driver);
+
+       memset(info, 0, SIZE_AVI_INFOFRAME);
+       hdmi_writel(hdmi_dev, CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI);
+       info[0] = 0x82;
+       info[1] = 0x02;
+       info[2] = 0x0D;
+       info[3] = info[0] + info[1] + info[2];
+       info[4] = (AVI_COLOR_MODE_RGB << 5);
+       info[5] =
+           (AVI_COLORIMETRY_NO_DATA << 6) | (AVI_CODED_FRAME_ASPECT_NO_DATA <<
+                                             4) |
+           ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME;
+       info[6] = 0;
+       info[7] = vic;
+       info[8] = 0;
+
+       /* Calculate AVI InfoFrame ChecKsum */
+       for (i = 4; i < SIZE_AVI_INFOFRAME; i++)
+               info[3] += info[i];
+
+       info[3] = 0x100 - info[3];
+
+       for (i = 0; i < SIZE_AVI_INFOFRAME; i++)
+               hdmi_writel(hdmi_dev, CONTROL_PACKET_ADDR + i, info[i]);
+}
+
+static int rk3036_hdmi_config_video(struct hdmi *hdmi_drv,
+                                               struct hdmi_video_para *vpara)
+{
+       int value;
+       struct fb_videomode *mode;
+       struct rk_hdmi_device *hdmi_dev = container_of(hdmi_drv,
+                                                      struct rk_hdmi_device,
+                                                      driver);
+
+       hdmi_dbg(hdmi_drv->dev, "[%s]\n", __func__);
+
+       if (vpara == NULL) {
+               hdmi_err(hdmi_drv->dev, "[%s] input parameter error\n",
+                        __func__);
+               return -1;
+       }
+
+       /* Output RGB as default */
+       vpara->output_color = VIDEO_OUTPUT_RGB444;
+       if (hdmi_drv->pwr_mode == LOWER_PWR)
+               rk3036_hdmi_set_pwr_mode(hdmi_drv, NORMAL);
+
+       /* Disable video and audio output */
+       hdmi_writel(hdmi_dev, AV_MUTE, v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1));
+
+       /* Input video mode is SDR RGB24bit, Data enable signal from external */
+       hdmi_writel(hdmi_dev, VIDEO_CONTRL1,
+                   v_VIDEO_INPUT_FORMAT(VIDEO_INPUT_SDR_RGB444) |
+                   v_DE_EXTERNAL);
+       hdmi_writel(hdmi_dev, VIDEO_CONTRL2,
+                   v_VIDEO_INPUT_BITS(VIDEO_INPUT_8BITS) |
+                   v_VIDEO_OUTPUT_FORMAT(vpara->output_color & 0xFF));
+
+       /* Set HDMI Mode */
+       hdmi_writel(hdmi_dev, HDCP_CTRL, v_HDMI_DVI(vpara->output_mode));
+
+       /* Enable or disalbe color space convert */
+       if (vpara->input_color != vpara->output_color)
+               value = v_SOF_DISABLE | v_CSC_ENABLE;
+       else
+               value = v_SOF_DISABLE;
+       hdmi_writel(hdmi_dev, VIDEO_CONTRL3, value);
+
+       /* Set ext video timing */
+#if 1
+       hdmi_writel(hdmi_dev, VIDEO_TIMING_CTL, 0);
+       mode = (struct fb_videomode *)hdmi_vic_to_videomode(vpara->vic);
+       if (mode == NULL) {
+               hdmi_err(hdmi_drv->dev, "[%s] not found vic %d\n", __func__,
+                        vpara->vic);
+               return -ENOENT;
+       }
+       hdmi_drv->tmdsclk = mode->pixclock;
+#else
+       value = v_EXTERANL_VIDEO(1) | v_INETLACE(mode->vmode);
+       if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
+               value |= v_HSYNC_POLARITY(1);
+       if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
+               value |= v_VSYNC_POLARITY(1);
+       hdmi_writel(hdmi_dev, VIDEO_TIMING_CTL, value);
+
+       value = mode->left_margin + mode->xres + mode->right_margin +
+           mode->hsync_len;
+       hdmi_writel(hdmi_dev, VIDEO_EXT_HTOTAL_L, value & 0xFF);
+       hdmi_writel(hdmi_dev, VIDEO_EXT_HTOTAL_H, (value >> 8) & 0xFF);
+
+       value = mode->left_margin + mode->right_margin + mode->hsync_len;
+       hdmi_writel(hdmi_dev, VIDEO_EXT_HBLANK_L, value & 0xFF);
+       hdmi_writel(hdmi_dev, VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF);
+
+       value = mode->left_margin + mode->hsync_len;
+       hdmi_writel(hdmi_dev, VIDEO_EXT_HDELAY_L, value & 0xFF);
+       hdmi_writel(hdmi_dev, VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF);
+
+       value = mode->hsync_len;
+       hdmi_writel(hdmi_dev, VIDEO_EXT_HDURATION_L, value & 0xFF);
+       hdmi_writel(hdmi_dev, VIDEO_EXT_HDURATION_H, (value >> 8) & 0xFF);
+
+       value = mode->upper_margin + mode->yres + mode->lower_margin +
+           mode->vsync_len;
+       hdmi_writel(hdmi_dev, VIDEO_EXT_VTOTAL_L, value & 0xFF);
+       hdmi_writel(hdmi_dev, VIDEO_EXT_VTOTAL_H, (value >> 8) & 0xFF);
+
+       value = mode->upper_margin + mode->vsync_len + mode->lower_margin;
+       hdmi_writel(hdmi_dev, VIDEO_EXT_VBLANK, value & 0xFF);
+
+       if (vpara->vic == HDMI_720x480p_60Hz_4_3 ||
+               vpara->vic == HDMI_720x480p_60Hz_16_9)
+               value = 42;
+       else
+               value = mode->upper_margin + mode->vsync_len;
+
+       hdmi_writel(hdmi_dev, VIDEO_EXT_VDELAY, value & 0xFF);
+
+       value = mode->vsync_len;
+       hdmi_writel(hdmi_dev, VIDEO_EXT_VDURATION, value & 0xFF);
+#endif
+
+       if (vpara->output_mode == OUTPUT_HDMI) {
+               rk3036_hdmi_config_avi(hdmi_drv, vpara->vic,
+                                       vpara->output_color);
+               hdmi_dbg(hdmi_drv->dev, "[%s] sucess output HDMI.\n", __func__);
+       } else {
+               hdmi_dbg(hdmi_drv->dev, "[%s] sucess output DVI.\n", __func__);
+       }
+
+       /* rk3028a */
+       hdmi_writel(hdmi_dev, PHY_PRE_DIV_RATIO, 0x1e);
+       hdmi_writel(hdmi_dev, PHY_FEEDBACK_DIV_RATIO_LOW, 0x2c);
+       hdmi_writel(hdmi_dev, PHY_FEEDBACK_DIV_RATIO_HIGH, 0x01);
+
+       return 0;
+}
+
+static void rk3036_hdmi_config_aai(struct hdmi *hdmi_drv)
+{
+       int i;
+       char info[SIZE_AUDIO_INFOFRAME];
+       struct rk_hdmi_device *hdmi_dev = container_of(hdmi_drv,
+                                                      struct rk_hdmi_device,
+                                                      driver);
+
+       memset(info, 0, SIZE_AUDIO_INFOFRAME);
+
+       info[0] = 0x84;
+       info[1] = 0x01;
+       info[2] = 0x0A;
+
+       info[3] = info[0] + info[1] + info[2];
+       for (i = 4; i < SIZE_AUDIO_INFOFRAME; i++)
+               info[3] += info[i];
+
+       info[3] = 0x100 - info[3];
+
+       hdmi_writel(hdmi_dev, CONTROL_PACKET_BUF_INDEX, INFOFRAME_AAI);
+       for (i = 0; i < SIZE_AUDIO_INFOFRAME; i++)
+               hdmi_writel(hdmi_dev, CONTROL_PACKET_ADDR + i, info[i]);
+}
+
+static int rk3036_hdmi_config_audio(struct hdmi *hdmi_drv,
+                                               struct hdmi_audio *audio)
+{
+       int rate, N, channel, mclk_fs;
+       struct rk_hdmi_device *hdmi_dev = container_of(hdmi_drv,
+                                                      struct rk_hdmi_device,
+                                                      driver);
+
+       if (audio->channel < 3)
+               channel = I2S_CHANNEL_1_2;
+       else if (audio->channel < 5)
+               channel = I2S_CHANNEL_3_4;
+       else if (audio->channel < 7)
+               channel = I2S_CHANNEL_5_6;
+       else
+               channel = I2S_CHANNEL_7_8;
+
+       switch (audio->rate) {
+       case HDMI_AUDIO_FS_32000:
+               rate = AUDIO_32K;
+               N = N_32K;
+               mclk_fs = MCLK_384FS;
+               break;
+       case HDMI_AUDIO_FS_44100:
+               rate = AUDIO_441K;
+               N = N_441K;
+               mclk_fs = MCLK_256FS;
+               break;
+       case HDMI_AUDIO_FS_48000:
+               rate = AUDIO_48K;
+               N = N_48K;
+               mclk_fs = MCLK_256FS;
+               break;
+       case HDMI_AUDIO_FS_88200:
+               rate = AUDIO_882K;
+               N = N_882K;
+               mclk_fs = MCLK_128FS;
+               break;
+       case HDMI_AUDIO_FS_96000:
+               rate = AUDIO_96K;
+               N = N_96K;
+               mclk_fs = MCLK_128FS;
+               break;
+       case HDMI_AUDIO_FS_176400:
+               rate = AUDIO_1764K;
+               N = N_1764K;
+               mclk_fs = MCLK_128FS;
+               break;
+       case HDMI_AUDIO_FS_192000:
+               rate = AUDIO_192K;
+               N = N_192K;
+               mclk_fs = MCLK_128FS;
+               break;
+       default:
+               dev_err(hdmi_drv->dev, "[%s] not support such sample rate %d\n",
+                       __func__, audio->rate);
+               return -ENOENT;
+       }
+
+       /* set_audio source I2S */
+       if (HDMI_CODEC_SOURCE_SELECT == INPUT_IIS) {
+               hdmi_writel(hdmi_dev, AUDIO_CTRL1, 0x00);
+               hdmi_writel(hdmi_dev, AUDIO_SAMPLE_RATE, rate);
+               hdmi_writel(hdmi_dev, AUDIO_I2S_MODE,
+                           v_I2S_MODE(I2S_STANDARD) | v_I2S_CHANNEL(channel));
+               hdmi_writel(hdmi_dev, AUDIO_I2S_MAP, 0x00);
+               /* no swap */
+               hdmi_writel(hdmi_dev, AUDIO_I2S_SWAPS_SPDIF, 0);
+       } else {
+               hdmi_writel(hdmi_dev, AUDIO_CTRL1, 0x08);
+               /* no swap */
+               hdmi_writel(hdmi_dev, AUDIO_I2S_SWAPS_SPDIF, 0);
+       }
+
+       /* Set N value */
+       hdmi_writel(hdmi_dev, AUDIO_N_H, (N >> 16) & 0x0F);
+       hdmi_writel(hdmi_dev, AUDIO_N_M, (N >> 8) & 0xFF);
+       hdmi_writel(hdmi_dev, AUDIO_N_L, N & 0xFF);
+       rk3036_hdmi_config_aai(hdmi_drv);
+
+       return 0;
+}
+
+void rk3036_hdmi_control_output(struct hdmi *hdmi_drv, int enable)
+{
+       int mutestatus = 0;
+       struct rk_hdmi_device *hdmi_dev = container_of(hdmi_drv,
+                                                      struct rk_hdmi_device,
+                                                      driver);
+
+       if (enable) {
+               if (hdmi_drv->pwr_mode == LOWER_PWR)
+                       rk3036_hdmi_set_pwr_mode(hdmi_drv, NORMAL);
+               hdmi_readl(hdmi_dev, AV_MUTE, &mutestatus);
+               if (mutestatus && (m_AUDIO_MUTE | m_VIDEO_BLACK)) {
+                       hdmi_writel(hdmi_dev, AV_MUTE,
+                                   v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));
+               }
+               rk3036_hdmi_sys_power(hdmi_drv, true);
+               rk3036_hdmi_sys_power(hdmi_drv, false);
+               rk3036_hdmi_sys_power(hdmi_drv, true);
+               hdmi_writel(hdmi_dev, 0xce, 0x00);
+               delay100us();
+               hdmi_writel(hdmi_dev, 0xce, 0x01);
+       } else {
+               hdmi_writel(hdmi_dev, AV_MUTE,
+                           v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1));
+       }
+}
+
+int rk3036_hdmi_removed(struct hdmi *hdmi_drv)
+{
+       dev_info(hdmi_drv->dev, "Removed.\n");
+       if (hdmi_drv->hdcp_power_off_cb)
+               hdmi_drv->hdcp_power_off_cb();
+       rk3036_hdmi_set_pwr_mode(hdmi_drv, LOWER_PWR);
+
+       return HDMI_ERROR_SUCESS;
+}
+
+void rk3036_hdmi_irq(struct hdmi *hdmi_drv)
+{
+       u32 interrupt = 0;
+       struct rk_hdmi_device *hdmi_dev = container_of(hdmi_drv,
+                                                      struct rk_hdmi_device,
+                                                      driver);
+       hdmi_readl(hdmi_dev, HDMI_STATUS, &interrupt);
+       if(interrupt) {
+               hdmi_writel(hdmi_dev, HDMI_STATUS, interrupt);
+       }
+       if (interrupt & m_INT_HOTPLUG) {
+               if (hdmi_drv->state == HDMI_SLEEP)
+                       hdmi_drv->state = WAIT_HOTPLUG;
+
+               queue_delayed_work(hdmi_drv->workqueue, &hdmi_drv->delay_work,
+                                  msecs_to_jiffies(40));
+
+       }/*plug out*/
+
+       if (hdmi_drv->hdcp_irq_cb)
+               hdmi_drv->hdcp_irq_cb(0);
+}
+
+static void rk3036_hdmi_reset(struct hdmi *hdmi_drv)
+{
+       u32 val = 0;
+       u32 msk = 0;
+       struct rk_hdmi_device *hdmi_dev = container_of(hdmi_drv,
+                                                      struct rk_hdmi_device,
+                                                      driver);
+
+       hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_RST_DIGITAL, v_NOT_RST_DIGITAL);
+       delay100us();
+       hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_RST_ANALOG, v_NOT_RST_ANALOG);
+       delay100us();
+       msk = m_REG_CLK_INV | m_REG_CLK_SOURCE | m_POWER | m_INT_POL;
+       val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH;
+       hdmi_msk_reg(hdmi_dev, SYS_CTRL, msk, val);
+
+       rk3036_hdmi_set_pwr_mode(hdmi_drv, LOWER_PWR);
+}
+
+int rk3036_hdmi_initial(struct hdmi *hdmi_drv)
+{
+       int rc = HDMI_ERROR_SUCESS;
+
+       hdmi_drv->pwr_mode = NORMAL;
+       hdmi_drv->remove = rk3036_hdmi_removed;
+       hdmi_drv->control_output = rk3036_hdmi_control_output;
+       hdmi_drv->config_video = rk3036_hdmi_config_video;
+       hdmi_drv->config_audio = rk3036_hdmi_config_audio;
+       hdmi_drv->detect_hotplug = rk3036_hdmi_detect_hotplug;
+       hdmi_drv->read_edid = rk3036_hdmi_read_edid;
+       hdmi_drv->insert    = rk3036_hdmi_insert;
+
+       rk3036_hdmi_reset_pclk();
+       rk3036_hdmi_reset(hdmi_drv);
+
+       if (hdmi_drv->hdcp_power_on_cb)
+               rc = hdmi_drv->hdcp_power_on_cb();
+
+       return rc;
+}
diff --git a/drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdmi_hw.h b/drivers/video/rockchip/hdmi/chips/rk3036/rk3036_hdmi_hw.h
new file mode 100755 (executable)
index 0000000..70f3841
--- /dev/null
@@ -0,0 +1,323 @@
+#ifndef _RK3036_HDMI_HW_H
+#define _RK3036_HDMI_HW_H
+
+#include <linux/rockchip/iomap.h>
+enum PWR_MODE {
+       NORMAL,
+       LOWER_PWR,
+};
+enum {
+       OUTPUT_DVI = 0,
+       OUTPUT_HDMI
+};
+
+#ifdef RK616_USE_MCLK_12M
+#define HDMI_SYS_FREG_CLK        12000000
+#else
+#define HDMI_SYS_FREG_CLK        11289600
+#endif
+
+#define HDMI_SCL_RATE            (100*1000)
+#define DDC_BUS_FREQ_L                 0x4b
+#define DDC_BUS_FREQ_H                 0x4c
+
+#define SYS_CTRL                       0x00
+#define m_RST_ANALOG           (1 << 6)
+#define v_RST_ANALOG           (0 << 6)
+#define v_NOT_RST_ANALOG       (1 << 6)
+
+#define m_RST_DIGITAL          (1 << 5)
+#define v_RST_DIGITAL          (0 << 5)
+#define v_NOT_RST_DIGITAL      (1 << 5)
+
+#define m_REG_CLK_INV          (1 << 4)
+#define v_REG_CLK_NOT_INV      (0 << 4)
+#define v_REG_CLK_INV          (1 << 4)
+#define m_VCLK_INV             (1 << 3)
+#define v_VCLK_NOT_INV         (0 << 3)
+#define v_VCLK_INV             (1 << 3)
+#define m_REG_CLK_SOURCE       (1 << 2)
+#define v_REG_CLK_SOURCE_TMDS  (0 << 2)
+#define v_REG_CLK_SOURCE_SYS   (1 << 2)
+#define m_POWER                        (1 << 1)
+#define v_PWR_ON               (0 << 1)
+#define v_PWR_OFF              (1 << 1)
+#define m_INT_POL              (1 << 0)
+#define v_INT_POL_HIGH         1
+#define v_INT_POL_LOW          0
+
+#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_ACTIVE_VSYNC      (1 << 5)
+#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_MASK_INT_HOTPLUG      (1 << 5)
+       #define m_INT_HOTPLUG           (1 << 1)
+
+
+#define HDMI_COLORBAR                   0xc9
+
+#define PHY_SYNC                       0xce    /* sync phy parameter */
+#define PHY_SYS_CTL                    0xe0
+#define m_TMDS_CLK_SOURCE      (1 << 5)
+#define v_TMDS_FROM_PLL                (0 << 5)
+#define v_TMDS_FROM_GEN                (1 << 5)
+#define m_PHASE_CLK            (1 << 4)
+#define v_DEFAULT_PHASE                (0 << 4)
+#define v_SYNC_PHASE           (1 << 4)
+#define m_TMDS_CURRENT_PWR     (1 << 3)
+#define v_TURN_ON_CURRENT      (0 << 3)
+#define v_CAT_OFF_CURRENT      (1 << 3)
+#define m_BANDGAP_PWR          (1 << 2)
+#define v_BANDGAP_PWR_UP       (0 << 2)
+#define v_BANDGAP_PWR_DOWN     (1 << 2)
+#define m_PLL_PWR              (1 << 1)
+#define v_PLL_PWR_UP           (0 << 1)
+#define v_PLL_PWR_DOWN         (1 << 1)
+#define m_TMDS_CHG_PWR         (1 << 0)
+#define v_TMDS_CHG_PWR_UP      (0 << 0)
+#define v_TMDS_CHG_PWR_DOWN    (1 << 0)
+
+#define PHY_CHG_PWR                    0xe1
+#define v_CLK_CHG_PWR(n)       ((n & 1) << 3)
+#define v_DATA_CHG_PWR(n)      ((n & 7) << 0)
+
+#define PHY_DRIVER                     0xe2
+#define v_CLK_MAIN_DRIVER(n)   (n << 4)
+#define v_DATA_MAIN_DRIVER(n)  (n << 0)
+
+#define PHY_PRE_EMPHASIS               0xe3
+#define v_PRE_EMPHASIS(n)      ((n & 7) << 4)
+#define v_CLK_PRE_DRIVER(n)    ((n & 3) << 2)
+#define v_DATA_PRE_DRIVER(n)   ((n & 3) << 0)
+
+#define PHY_FEEDBACK_DIV_RATIO_LOW     0xe7
+#define v_FEEDBACK_DIV_LOW(n)  (n & 0xff)
+#define PHY_FEEDBACK_DIV_RATIO_HIGH    0xe8
+#define v_FEEDBACK_DIV_HIGH(n) (n & 1)
+
+#define PHY_PRE_DIV_RATIO              0xed
+#define v_PRE_DIV_RATIO(n)     (n & 0x1f)
+
+static inline int hdmi_readl(struct rk_hdmi_device *hdmi_dev, u16 offset,
+                            u32 *val)
+{
+       int ret = 0;
+
+       *val = readl_relaxed(hdmi_dev->regbase + (offset) * 0x04);
+       return ret;
+}
+
+static inline int hdmi_writel(struct rk_hdmi_device *hdmi_dev, u16 offset,
+                             u32 val)
+{
+       int ret = 0;
+
+       writel_relaxed(val, hdmi_dev->regbase + (offset) * 0x04);
+       return ret;
+}
+
+static inline int hdmi_msk_reg(struct rk_hdmi_device *hdmi_dev, u16 offset,
+                              u32 msk, u32 val)
+{
+       int ret = 0;
+       u32 temp;
+
+       temp = readl_relaxed(hdmi_dev->regbase + (offset) * 0x04) & (0xFF - (msk));
+       writel_relaxed(temp | ((val) & (msk)), hdmi_dev->regbase + (offset) * 0x04);
+       return ret;
+}
+static inline void rk3036_hdmi_reset_pclk(void)
+{
+       writel_relaxed(0x00010001, RK_CRU_VIRT+ 0x128);
+       msleep(100);
+       writel_relaxed(0x00010000, RK_CRU_VIRT + 0x128);
+}
+
+extern int rk3036_hdmi_initial(struct hdmi *hdmi);
+extern void rk3036_hdmi_irq(struct hdmi *hdmi);
+
+#endif
index cb61763ac68cc0c508668999ad2417299b0fed42..fe65b3760f7696972e795e7c15e68ea8ae725dc8 100755 (executable)
@@ -124,7 +124,7 @@ int hdmi_set_info(struct rk_screen *screen, unsigned int vic)
        screen->hdmi_resolution = hdmi_mode[i].flag;
 
        /* Pin polarity */
-#if defined(CONFIG_HDMI_RK616) && !defined(CONFIG_ARCH_RK3026) && !defined(SOC_CONFIG_RK3036)
+#if defined(CONFIG_HDMI_RK616) && !defined(CONFIG_ARCH_RK3026)
        screen->pin_hsync = 0;
        screen->pin_vsync = 0;
 #else