config HDMI_RK30
- bool "rk30 hdmi support"
+ bool "RK30 HDMI support"
depends on LCDC_RK30
select FB_MODE_HELPERS
-# default y
help
Support rk30 hdmi if you say y here
-
+
+config HDMI_RK30_DEBUG
+ bool "RK30 HDMI Debugging"
+ depends on HDMI_RK30 && LCDC_RK30
+ default n
+ help
+ Enableds verbose debugging the the HDMI drivers
+
+source "drivers/video/rockchip/hdmi/hdcp/Kconfig"
\ No newline at end of file
+#
+# Makefile for HDMI linux kernel module.
+#
+
+ccflags-$(CONFIG_HDMI_RK30_DEBUG) = -DDEBUG -DHDMI_DEBUG
+
obj-$(CONFIG_HDMI_RK30) += rk30_hdmi_hw.o rk30_hdmi_edid.o rk30_hdmi_lcdc.o rk30_hdmi_task.o rk30_hdmi_sysfs.o rk30_hdmi.o
+obj-$(CONFIG_HDCP_RK30) += hdcp/
--- /dev/null
+config HDCP_RK30
+ bool "RK30 HDCP support"
+ depends on LCDC_RK30 && HDMI_RK30
+ default n
+ help
+ HDCP Interface. This adds the High Definition Content Protection Interface.
+ See http://www.digital-cp.com/ for HDCP specification.
+
+config HDCP_RK30_DEBUG
+ bool "RK30 HDCP Debugging"
+ depends on HDCP_RK30
+ default n
+ help
+ Enableds verbose debugging the the HDCP drivers
--- /dev/null
+#
+# Makefile for HDCP linux kernel module.
+#
+
+ccflags-$(CONFIG_HDCP_RK30_DEBUG) = -DDEBUG -DHDCP_DEBUG
+
+obj-$(CONFIG_HDCP_RK30) += hdcp.o
+hdcp-y := rk30_hdcp.o rk30_hdmi_hdcp.o
--- /dev/null
+#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 "../rk30_hdmi.h"
+#include "../rk30_hdmi_hw.h"
+#include "rk30_hdmi_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;
+ }
+
+ rk30_hdcp_disable();
+ rk30_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 = rk30_hdcp_start_authentication();
+
+ if (status != HDCP_OK) {
+ DBG("HDCP: authentication failed");
+ hdcp_wq_authentication_failure();
+ } else {
+ hdcp->hdcp_state = HDCP_WAIT_KSV_LIST;
+ }
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_wq_check_bksv
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_check_bksv(void)
+{
+ int status = HDCP_OK;
+
+ DBG("Check BKSV start");
+
+ status = rk30_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)
+{
+ printk(KERN_INFO "HDCP: authentication pass");
+ rk30_hdmi_control_output(true);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_wq_disable
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_disable(int event)
+{
+ printk(KERN_INFO "HDCP: disabled");
+
+ hdcp_cancel_work(&hdcp->pending_wq_event);
+ rk30_hdcp_disable();
+ if(event == HDCP_DISABLE_CTL) {
+ hdcp->hdcp_state = HDCP_DISABLED;
+ if(hdcp->hdmi_state == HDMI_STARTED)
+ rk30_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 interrupt)
+{
+ DBG("%s 0x%x", __FUNCTION__, interrupt);
+ if(interrupt & 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(interrupt & (m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY))
+ hdcp_submit_work(HDCP_KSV_LIST_RDY_EVENT, 0);
+ else if(interrupt & m_INT_AUTH_DONE)
+ hdcp_submit_work(HDCP_AUTH_PASS_EVENT, 0);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_power_on_cb
+ *-----------------------------------------------------------------------------
+ */
+static int hdcp_power_on_cb(void)
+{
+ DBG("%s", __FUNCTION__);
+ return rk30_hdcp_load_key2mem(hdcp->keys);
+}
+
+/*-----------------------------------------------------------------------------
+ * 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(2000));
+}
+
+// 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);
+
+ rk30_hdcp_load_key2mem(hdcp->keys);
+ printk(KERN_INFO "HDCP: loaded hdcp key success\n");
+
+ if(fw->size > HDCP_KEY_SIZE) {
+ DBG("%s invalid key size %d", __FUNCTION__, fw->size - HDCP_KEY_SIZE);
+ 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 rk30_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;
+ }
+
+ rk30_hdmi_register_hdcp_callbacks( hdcp_start_frame_cb,
+ hdcp_irq_cb,
+ hdcp_power_on_cb,
+ hdcp_power_off_cb);
+
+ DBG("%s success %u", __FUNCTION__, jiffies_to_msecs(jiffies));
+ 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 rk30_hdcp_exit(void)
+{
+ if(hdcp) {
+ mutex_lock(&hdcp->lock);
+ rk30_hdmi_register_hdcp_callbacks(0, 0, 0, 0);
+ device_remove_file(mdev.this_device, &dev_attr_enable);
+ misc_deregister(&mdev);
+ destroy_workqueue(hdcp->workqueue);
+ if(hdcp->keys)
+ kfree(hdcp->keys);
+ if(hdcp->invalidkeys)
+ kfree(hdcp->invalidkeys);
+ mutex_unlock(&hdcp->lock);
+ kfree(hdcp);
+ }
+}
+
+module_init(rk30_hdcp_init);
+module_exit(rk30_hdcp_exit);
\ No newline at end of file
--- /dev/null
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <mach/io.h>
+#include "../rk30_hdmi.h"
+#include "../rk30_hdmi_hw.h"
+#include "rk30_hdmi_hdcp.h"
+
+static void rk30_hdcp_write_mem(int addr_8, char value)
+{
+ int temp;
+ int addr_32 = addr_8 - addr_8%4;
+ int shift = (addr_8%4) * 8;
+
+ temp = HDMIRdReg(addr_32);
+ temp &= ~(0xff << shift);
+ temp |= value << shift;
+// printk("temp is %08x\n", temp);
+ HDMIWrReg(addr_32, temp);
+}
+
+int rk30_hdcp_load_key2mem(struct hdcp_keys *key)
+{
+ int i;
+
+ if(key == NULL) return HDMI_ERROR_FALSE;
+
+ HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV);
+
+ for(i = 0; i < 7; i++)
+ rk30_hdcp_write_mem(HDCP_RAM_KEY_KSV1 + i, key->KSV[i]);
+ for(i = 0; i < 7; i++)
+ rk30_hdcp_write_mem(HDCP_RAM_KEY_KSV2 + i, key->KSV[i]);
+ for(i = 0; i < HDCP_PRIVATE_KEY_SIZE; i++)
+ rk30_hdcp_write_mem(HDCP_RAM_KEY_PRIVATE + i, key->DeviceKey[i]);
+ for(i = 0; i < HDCP_KEY_SHA_SIZE; i++)
+ rk30_hdcp_write_mem(HDCP_RAM_KEY_PRIVATE + HDCP_PRIVATE_KEY_SIZE + i, key->sha1[i]);
+
+ HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV | 0x20);
+ return HDCP_OK;
+}
+
+void rk30_hdcp_disable(void)
+{
+ int temp;
+ // Diable HDCP Interrupt
+ HDMIWrReg(INTR_MASK2, 0x00);
+ // Stop and Reset HDCP
+ HDMIMskReg(temp, HDCP_CTRL, m_HDCP_FRAMED_ENCRYPED | m_HDCP_AUTH_STOP | m_HDCP_RESET,
+ v_HDCP_FRAMED_ENCRYPED(0) | v_HDCP_AUTH_STOP(1) | v_HDCP_RESET(1) );
+}
+
+static int rk30_hdcp_load_key(void)
+{
+ int value, temp = 0;
+
+ if(hdcp->keys == NULL) {
+ pr_err("[%s] HDCP key not loaded.\n", __FUNCTION__);
+ return HDCP_KEY_ERR;
+ }
+
+ value = HDMIRdReg(HDCP_KEY_MEM_CTRL);
+ //Check HDCP key loaded from external HDCP memory
+ while((value & (m_KSV_VALID | m_KEY_VALID | m_KEY_READY)) != (m_KSV_VALID | m_KEY_VALID | m_KEY_READY)) {
+ if(temp > 10) {
+ pr_err("[%s] loaded hdcp key is incorrectable %02x\n", __FUNCTION__, value & 0xFF);
+ return HDCP_KEY_ERR;
+ }
+ //Load HDCP Key from external HDCP memory
+ HDMIWrReg(HDCP_KEY_ACCESS_CTRL2, m_LOAD_HDCP_KEY);
+ msleep(1);
+ value = HDMIRdReg(HDCP_KEY_MEM_CTRL);
+ temp++;
+ }
+
+ return HDCP_OK;
+}
+
+
+int rk30_hdcp_start_authentication(void)
+{
+ int rc, temp;
+
+ rc = rk30_hdcp_load_key();
+ if(rc != HDCP_OK)
+ return rc;
+
+ // Set 100ms & 5 sec timer
+ switch(hdmi->vic)
+ {
+ case HDMI_720x576p_50Hz_4_3:
+ case HDMI_720x576p_50Hz_16_9:
+ case HDMI_1280x720p_50Hz:
+ case HDMI_1920x1080i_50Hz:
+ case HDMI_720x576i_50Hz_4_3:
+ case HDMI_720x576i_50Hz_16_9:
+ case HDMI_1920x1080p_50Hz:
+ HDMIWrReg(HDCP_TIMER_100MS, 5);
+ HDMIWrReg(HDCP_TIMER_5S, 250);
+ break;
+
+ default:
+ HDMIWrReg(HDCP_TIMER_100MS, 0x26);
+ HDMIWrReg(HDCP_TIMER_5S, 0x2c);
+ break;
+ }
+
+
+ // Enable HDCP Interrupt
+ HDMIWrReg(INTR_MASK2, m_INT_HDCP_ERR | m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY | m_INT_AUTH_DONE | m_INT_AUTH_READY);
+ // Start HDCP
+ HDMIMskReg(temp, HDCP_CTRL, m_HDCP_AUTH_START | m_HDCP_FRAMED_ENCRYPED, v_HDCP_AUTH_START(1) | v_HDCP_FRAMED_ENCRYPED(0));
+
+ return HDCP_OK;
+}
+
+int rk30_hdcp_check_bksv(void)
+{
+ int i, temp;
+ char bksv[5];
+ char *invalidkey;
+
+ temp = HDMIRdReg(HDCP_BCAPS);
+ DBG("Receiver capacity is 0x%02x", temp);
+
+#ifdef DEBUG
+ if(temp & m_HDMI_RECEIVED)
+ DBG("Receiver support HDMI");
+ if(temp & m_REPEATER)
+ DBG("Receiver is a repeater");
+ if(temp & m_DDC_FAST)
+ DBG("Receiver support 400K DDC");
+ if(temp & m_1_1_FEATURE)
+ DBG("Receiver support 1.1 features, such as advanced cipher, EESS.");
+ if(temp & m_FAST_REAUTHENTICATION)
+ DBG("Receiver support fast reauthentication.");
+#endif
+
+ for(i = 0; i < 5; i++) {
+ bksv[i] = HDMIRdReg(HDCP_KSV_BYTE0 + (4 - i)*4) & 0xFF;
+ }
+
+ DBG("bksv is 0x%02x%02x%02x%02x%02x", bksv[0], bksv[1], bksv[2], bksv[3], bksv[4]);
+
+ for(i = 0; i < hdcp->invalidkey; i++)
+ {
+ invalidkey = hdcp->invalidkeys + i *5;
+ if(memcmp(bksv, invalidkey, 5) == 0) {
+ printk(KERN_ERR "HDCP: BKSV was revocated!!!\n");
+ HDMIMskReg(temp, HDCP_CTRL, m_HDCP_BKSV_FAILED | m_HDCP_FRAMED_ENCRYPED, v_HDCP_BKSV_FAILED(1) | v_HDCP_FRAMED_ENCRYPED(0));
+ return HDCP_KSV_ERR;
+ }
+ }
+ HDMIMskReg(temp, HDCP_CTRL, m_HDCP_BKSV_PASS | m_HDCP_FRAMED_ENCRYPED, v_HDCP_BKSV_PASS(1) | v_HDCP_FRAMED_ENCRYPED(1));
+ return HDCP_OK;
+}
--- /dev/null
+#ifndef __RK30_HDMI_HDCP_H__
+#define __RK30_HDMI_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
+
+/* Authentication retry times */
+#define HDCP_INFINITE_REAUTH 0x100
+
+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 rk30_hdcp_disable(void);
+extern int rk30_hdcp_start_authentication(void);
+extern int rk30_hdcp_check_bksv(void);
+extern int rk30_hdcp_load_key2mem(struct hdcp_keys *key);
+#endif /* __RK30_HDMI_HDCP_H__ */
\ No newline at end of file
extern void hdmi_register_display_sysfs(struct hdmi *hdmi, struct device *parent);\r
extern void hdmi_unregister_display_sysfs(struct hdmi *hdmi);\r
\r
+int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),\r
+ void (*hdcp_irq_cb)(int status),\r
+ int (*hdcp_power_on_cb)(void),\r
+ void (*hdcp_power_off_cb)(void))\r
+{\r
+ if(hdmi == NULL)\r
+ return HDMI_ERROR_FALSE;\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 exit early resume\n");\r
mutex_lock(&hdmi->enable_mutex);\r
hdmi->suspend = 0;\r
+ rk30_hdmi_initial();\r
if(hdmi->enable) {\r
enable_irq(hdmi->irq);\r
}\r
}\r
#endif\r
\r
-\r
-\r
-\r
-\r
static inline void hdmi_io_remap(void)\r
{\r
unsigned int value;\r
// Select LCDC0 as video source and enabled.\r
value = (HDMI_SOURCE_DEFAULT << 14) | (1 << 30);\r
writel(value, GRF_SOC_CON0 + RK30_GRF_BASE);\r
- \r
- // internal hclk = hdmi_hclk/20\r
- HDMIWrReg(0x800, 19);\r
}\r
\r
static int __devinit rk30_hdmi_probe (struct platform_device *pdev)\r
ret = -ENXIO;\r
goto err0;\r
}\r
- \r
+ hdmi->regbase_phy = res->start;\r
+ hdmi->regsize_phy = (res->end - res->start) + 1;\r
mem = request_mem_region(res->start, (res->end - res->start) + 1, pdev->name);\r
if (!mem)\r
{\r
goto err1;\r
}\r
\r
+ ret = rk30_hdmi_initial();\r
+ if(ret != HDMI_ERROR_SUCESS)\r
+ goto err1;\r
+ \r
hdmi_io_remap();\r
hdmi_sys_init();\r
\r
static int __devexit rk30_hdmi_remove(struct platform_device *pdev)\r
{\r
if(hdmi) {\r
+ mutex_lock(&hdmi->enable_mutex);\r
+ if(!hdmi->suspend && hdmi->enable)\r
+ disable_irq(hdmi->irq);\r
+ mutex_unlock(&hdmi->enable_mutex);\r
+ free_irq(hdmi->irq, NULL);\r
flush_workqueue(hdmi->workqueue);\r
destroy_workqueue(hdmi->workqueue);\r
#ifdef CONFIG_SWITCH\r
unregister_early_suspend(&hdmi->early_suspend);\r
#endif\r
iounmap((void*)hdmi->regbase);\r
- // release_mem_region(res->start,(res->end - res->start) + 1);\r
+ release_mem_region(hdmi->regbase_phy, hdmi->regsize_phy);\r
clk_disable(hdmi->hclk);\r
fb_destroy_modelist(&hdmi->edid.modelist);\r
if(hdmi->edid.audio)\r
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
-
+#include <asm/atomic.h>
#include<linux/rk_screen.h>
#include <linux/rk_fb.h>
#include "rk_hdmi.h"
struct clk *hclk; //HDMI AHP clk
int regbase;
int irq;
+ int regbase_phy;
+ int regsize_phy;
struct rk_lcdc_device_driver *lcdc;
#ifdef CONFIG_SWITCH
int display; // HDMI display status
int xscale; // x direction scale value
int yscale; // y directoon scale value
+
+ // call back for hdcp operatoion
+ void (*hdcp_cb)(void);
+ void (*hdcp_irq_cb)(int);
+ int (*hdcp_power_on_cb)(void);
+ void (*hdcp_power_off_cb)(void);
};
extern struct hdmi *hdmi;
extern int hdmi_ouputmode_select(struct hdmi *hdmi, int edid_ok);
extern int hdmi_switch_fb(struct hdmi *hdmi, int vic);
extern void hdmi_sys_remove(void);
+extern int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),
+ void (*hdcp_irq_cb)(int status),
+ int (*hdcp_power_on_cb)(void),
+ void (*hdcp_power_off_cb)(void));
#endif /* __RK30_HDMI_H__ */
\r
static int hdmi_edid_parse_base(unsigned char *buf, int *extend_num, struct hdmi_edid *pedid)\r
{\r
- int rc;\r
+ int rc, i;\r
\r
if(buf == NULL || extend_num == NULL)\r
return E_HDMI_EDID_PARAM;\r
msleep(1);
}
+int rk30_hdmi_initial(void)
+{
+ int rc = HDMI_ERROR_SUCESS;
+ // internal hclk = hdmi_hclk/20
+ HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV);
+
+ if(hdmi->hdcp_power_on_cb)
+ rc = hdmi->hdcp_power_on_cb();
+
+ return rc;
+}
+
static void rk30_hdmi_set_pwr_mode(int mode)
{
if(hdmi->pwr_mode == mode)
{
spin_lock_irqsave(&hdmi->irq_lock, flags);
interrupt = edid_result;
+ edid_result = 0;
spin_unlock_irqrestore(&hdmi->irq_lock, flags);
if(interrupt & (m_INT_EDID_ERR | m_INT_EDID_READY))
break;
break;
}
if(interrupt & m_INT_EDID_ERR)
- hdmi_dbg(hdmi->dev, "[%s] edid read error\n", __FUNCTION__);
+ hdmi_err(hdmi->dev, "[%s] edid read error\n", __FUNCTION__);
}
// Disable edid interrupt
rk30_hdmi_config_phy_reg(0x178, 0x00);
break;
default:
- hdmi_dbg(hdmi->dev, "not support such vic %d\n", vic);
+ hdmi_err(hdmi->dev, "not support such vic %d\n", vic);
break;
}
}
struct fb_videomode *mode;
hdmi_dbg(hdmi->dev, "[%s]\n", __FUNCTION__);
- if(vpara == NULL)
+ if(vpara == NULL) {
+ hdmi_err(hdmi->dev, "[%s] input parameter error\n", __FUNCTION__);
return -1;
-
+ }
if(hdmi->pwr_mode == PWR_SAVE_MODE_E)
rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_D);
if(hdmi->pwr_mode == PWR_SAVE_MODE_D || hdmi->pwr_mode == PWR_SAVE_MODE_A)
rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_B);
+
+ if(hdmi->hdcp_power_off_cb)
+ hdmi->hdcp_power_off_cb();
// Input video mode is RGB24bit, Data enable signal from external
HDMIMskReg(value, AV_CTRL1, m_INPUT_VIDEO_MODE | m_DE_SIGNAL_SELECT, \
mode = (struct fb_videomode *)hdmi_vic_to_videomode(vpara->vic);
if(mode == NULL)
{
- hdmi_dbg(hdmi->dev, "[%s] not found vic %d\n", __FUNCTION__, vpara->vic);
+ hdmi_err(hdmi->dev, "[%s] not found vic %d\n", __FUNCTION__, vpara->vic);
return -ENOENT;
}
value = v_EXT_VIDEO_ENABLE(1) | v_INTERLACE(mode->vmode);
N = N_192K;
break;
default:
- dev_err(hdmi->dev, "[%s] not support such sample rate %d\n", __FUNCTION__, audio->rate);
+ hdmi_err(hdmi->dev, "[%s] not support such sample rate %d\n", __FUNCTION__, audio->rate);
return -ENOENT;
}
switch(audio->word_length)
word_length = 0x0b;
break;
default:
- dev_err(hdmi->dev, "[%s] not support such word length %d\n", __FUNCTION__, audio->word_length);
+ hdmi_err(hdmi->dev, "[%s] not support such word length %d\n", __FUNCTION__, audio->word_length);
return -ENOENT;
}
//set_audio_if I2S
HDMIWrReg(VIDEO_SETTING2, 0x03);
}
else {
- // Switch to power save mode_d
- rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_D);
- // Switch to power save mode_e
- rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_E);
+ if(hdmi->pwr_mode == PWR_SAVE_MODE_B) {
+ // Switch to power save mode_d
+ rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_D);
+ }
+ if(hdmi->pwr_mode == PWR_SAVE_MODE_D) {
+ // Switch to power save mode_e
+ rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_E);
+ }
HDMIWrReg(VIDEO_SETTING2, 0x00);
rk30_hdmi_audio_reset();
}
// Disable color space convertion
HDMIWrReg(AV_CTRL2, v_CSC_ENABLE(0));
HDMIWrReg(CSC_CONFIG1, v_CSC_MODE(CSC_MODE_AUTO) | v_CSC_BRSWAP_DIABLE(1));
+ if(hdmi->hdcp_power_off_cb)
+ hdmi->hdcp_power_off_cb();
rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_A);
- }
+ }
+ dev_printk(KERN_INFO , hdmi->dev , "Removed.\n");
return HDMI_ERROR_SUCESS;
}
HDMIWrReg(SYS_CTRL, 0x10);
hdmi->pwr_mode = PWR_SAVE_MODE_A;
}
+ if(interrupt2 && hdmi->hdcp_irq_cb)
+ hdmi->hdcp_irq_cb(interrupt2);
}
return IRQ_HANDLED;
}
#define TMDS_CLOCK_MODE_MASK 0x3 << 6
#define TMDS_CLOCK_MODE(n) (n) << 6
+/* VIDEO_CTRL2 */
+#define VIDEO_SETTING2 0x114
+#define m_UNMUTE (1 << 7)
+#define m_MUTE (1 << 6)
+#define m_AUDIO_RESET (1 << 2)
+#define m_NOT_SEND_AUDIO (1 << 1)
+#define m_NOT_SEND_VIDEO (1 << 0)
+#define AV_UNMUTE (1 << 7) // Unmute video and audio, send normal video and audio data
+#define AV_MUTE (1 << 6) // Mute video and audio, send black video data and silent audio data
+#define AUDIO_CAPTURE_RESET (1 << 2) // Reset audio process logic, only available in pwr_e mode.
+#define NOT_SEND_AUDIO (1 << 1) // Send silent audio data
+#define NOT_SEND_VIDEO (1 << 0) // Send black video data
+
+/* Color Space Convertion Parameter*/
#define CSC_PARA_C0_H 0x60
#define CSC_PARA_C0_L 0x64
#define CSC_PARA_C1_H 0x68
#define v_CSC_VID_SELECT(n) (n << 1)
#define v_CSC_BRSWAP_DIABLE(n) (n)
-/* VIDEO_SETTING2 */
-#define VIDEO_SETTING2 0x114
-#define m_UNMUTE (1 << 7)
-#define m_MUTE (1 << 6)
-#define m_AUDIO_RESET (1 << 2)
-#define m_NOT_SEND_AUDIO (1 << 1)
-#define m_NOT_SEND_VIDEO (1 << 0)
-#define AV_UNMUTE (1 << 7) // Unmute video and audio, send normal video and audio data
-#define AV_MUTE (1 << 6) // Mute video and audio, send black video data and silent audio data
-#define AUDIO_CAPTURE_RESET (1 << 2) // Reset audio process logic, only available in pwr_e mode.
-#define NOT_SEND_AUDIO (1 << 1) // Send silent audio data
-#define NOT_SEND_VIDEO (1 << 0) // Send black video data
-
/* CONTROL_PACKET_BUF_INDEX */
#define CONTROL_PACKET_BUF_INDEX 0x17c
enum {
ACTIVE_ASPECT_RATE_14_9
};
-
-/* HDCP_CTRL */
-#define HDCP_CTRL 0x2bc
-
-enum {
- OUTPUT_DVI = 0,
- OUTPUT_HDMI
-};
-#define m_HDMI_DVI (1 << 1)
-#define v_HDMI_DVI(n) (n << 1)
-
+/* External Video Parameter Setting*/
#define EXT_VIDEO_PARA 0xC0
#define m_VSYNC_OFFSET (0xF << 4)
#define m_VSYNC_POLARITY (1 << 3)
#define v_PLLB_BIT16(n) (n << 4)
#define v_AML(n) (n)
+/* Interrupt Setting */
#define INTR_MASK1 0x248
-#define INTR_MASK2 0x24c
-#define INTR_MASK3 0x258
-#define INTR_MASK4 0x25c
#define INTR_STATUS1 0x250
+ #define m_INT_HOTPLUG (1 << 7)
+ #define m_INT_MSENS (1 << 6)
+ #define m_INT_VSYNC (1 << 5)
+ #define m_INT_AUDIO_FIFO_FULL (1 << 4)
+ #define m_INT_EDID_READY (1 << 2)
+ #define m_INT_EDID_ERR (1 << 1)
+#define INTR_MASK2 0x24c
#define INTR_STATUS2 0x254
+ #define m_INT_HDCP_ERR (1 << 7) // HDCP error detected
+ #define m_INT_BKSV_RPRDY (1 << 6) // BKSV list ready from repeater
+ #define m_INT_BKSV_RCRDY (1 << 5) // BKSV list ready from receiver
+ #define m_INT_AUTH_DONE (1 << 4) // HDCP authentication done
+ #define m_INT_AUTH_READY (1 << 3) // HDCP authentication ready
+#define INTR_MASK3 0x258
#define INTR_STATUS3 0x260
-#define INTR_STATUS4 0x264
-#define m_INT_HOTPLUG (1 << 7)
-#define m_INT_MSENS (1 << 6)
-#define m_INT_VSYNC (1 << 5)
-#define m_INT_AUDIO_FIFO_FULL (1 << 4)
-#define m_INT_EDID_READY (1 << 2)
-#define m_INT_EDID_ERR (1 << 1)
+#define INTR_MASK4 0x25c
+#define INTR_STATUS4 0x264
#define DDC_READ_FIFO_ADDR 0x200
#define DDC_BUS_FREQ_L 0x204
#define m_HOTPLUG_STATUS (1 << 7)
#define m_MSEN_STATUS (1 << 6)
+/* HDCP_CTRL */
+#define HDCP_CTRL 0x2bc
+ enum {
+ OUTPUT_DVI = 0,
+ OUTPUT_HDMI
+ };
+ #define m_HDCP_AUTH_START (1 << 7) // start hdcp
+ #define m_HDCP_BKSV_PASS (1 << 6) // bksv valid
+ #define m_HDCP_BKSV_FAILED (1 << 5) // bksv invalid
+ #define m_HDCP_FRAMED_ENCRYPED (1 << 4)
+ #define m_HDCP_AUTH_STOP (1 << 3) // stop hdcp
+ #define m_HDCP_ADV_CIPHER (1 << 2) // advanced cipher mode
+ #define m_HDMI_DVI (1 << 1)
+ #define m_HDCP_RESET (1 << 0) // reset hdcp
+ #define v_HDCP_AUTH_START(n) (n << 7)
+ #define v_HDCP_BKSV_PASS(n) (n << 6)
+ #define v_HDCP_BKSV_FAILED(n) (n << 5)
+ #define v_HDCP_FRAMED_ENCRYPED(n) (n << 4)
+ #define v_HDCP_AUTH_STOP(n) (n << 3)
+ #define v_HDCP_ADV_CIPHER(n) (n << 2)
+ #define v_HDMI_DVI(n) (n << 1)
+ #define v_HDCP_RESET(n) (n << 0)
+#define HDCP_CTRL2 0x340
+
+/* HDCP Key Memory Access Control */
+#define HDCP_KEY_ACCESS_CTRL1 0x338
+#define HDCP_KEY_ACCESS_CTRL2 0x33c
+ #define m_LOAD_FACSIMILE_HDCP_KEY (1 << 1)
+ #define m_LOAD_HDCP_KEY (1 << 0)
+/* HDCP Key Memory Control */
+#define HDCP_KEY_MEM_CTRL 0x348
+ #define m_USE_KEY1 (1 << 6)
+ #define m_USE_KEY2 (1 << 5)
+ #define m_LOAD_AKSV (1 << 4)
+ #define m_KSV_SELECTED (1 << 3)
+ #define m_KSV_VALID (1 << 2)
+ #define m_KEY_VALID (1 << 1)
+ #define m_KEY_READY (1 << 0)
+ #define v_USE_KEY1(n) (n << 6)
+ #define v_USE_KEY2(n) (n << 5)
+ #define v_LOAD_AKSV(n) (n << 4)
+
+/* HDCP B device capacity */
+#define HDCP_BCAPS 0x2f8
+ #define m_HDMI_RECEIVED (1 << 7) //If HDCP receiver support HDMI, this bit must be 1.
+ #define m_REPEATER (1 << 6)
+ #define m_KSV_FIFO_READY (1 << 5)
+ #define m_DDC_FAST (1 << 4)
+ #define m_1_1_FEATURE (1 << 1)
+ #define m_FAST_REAUTHENTICATION (1 << 0) //For HDMI, this function is supported whether this bit is enabled or not.
+
+/* HDCP KSV Value */
+#define HDCP_KSV_BYTE0 0x2fc
+#define HDCP_KSV_BYTE1 0x300
+#define HDCP_KSV_BYTE2 0x304
+#define HDCP_KSV_BYTE3 0x308
+#define HDCP_KSV_BYTE4 0x30c
+
+/* HDCP 100 ms timer */
+#define HDCP_TIMER_100MS 0x324
+/* HDCP 5s timer */
+#define HDCP_TIMER_5S 0x328
+
+/* HDCP Key ram address */
+#define HDCP_RAM_KEY_KSV1 0x400
+#define HDCP_RAM_KEY_KSV2 0x407
+#define HDCP_RAM_KEY_PRIVATE 0x40e
+#define HDCP_KEY_LENGTH 0x13C
+
+
+#define HDCP_ENABLE_HW_AUTH // Enable hardware authentication mode
+#define HDMI_INTERANL_CLK_DIV 0x19
#define HDMIRdReg(addr) __raw_readl(hdmi->regbase + addr)
#define HDMIWrReg(addr, val) __raw_writel((val), hdmi->regbase + addr);
CSC_ITU709_16_235_TO_RGB_0_255 //YCbCr 16-235 input to RGB 0-255 output according BT709
};
+extern int rk30_hdmi_initial(void);
extern int rk30_hdmi_detect_hotplug(void);
extern int rk30_hdmi_read_edid(int block, unsigned char *buff);
extern int rk30_hdmi_removed(void);
extern int rk30_hdmi_config_video(struct rk30_hdmi_video_para *vpara);
extern int rk30_hdmi_config_audio(struct hdmi_audio *audio);
extern void rk30_hdmi_control_output(int enable);
+
#endif
\ No newline at end of file
hdmi_sys_sleep();
do {
+ hdmi_sys_show_state(hdmi->state);
state_last = hdmi->state;
switch(hdmi->state)
{
if(hdmi->display != HDMI_ENABLE) {
rk30_hdmi_control_output(HDMI_ENABLE);
hdmi->display = HDMI_ENABLE;
+ if(hdmi->hdcp_cb) {
+ hdmi->hdcp_cb();
+ }
}
+
if(hdmi->wait == 1) {
complete(&hdmi->complete);
hdmi->wait = 0;
}
if(hdmi->state != state_last)
trytimes = 0;
-
- hdmi_sys_show_state(hdmi->state);
+
}while((hdmi->state != state_last || (rc != HDMI_ERROR_SUCESS) ) && trytimes < HDMI_MAX_TRY_TIMES);
- if(trytimes == HDMI_MAX_TRY_TIMES)
- {
- if(hdmi->hotplug) {
- hdmi_sys_remove();
- hdmi->hotplug = HDMI_HPD_REMOVED;
- hdmi_sys_sleep();
-
- }
- }
+// if(trytimes == HDMI_MAX_TRY_TIMES)
+// {
+// if(hdmi->hotplug) {
+// hdmi_sys_remove();
+// hdmi->hotplug = HDMI_HPD_REMOVED;
+// hdmi_sys_sleep();
+//
+// }
+// }
hdmi_dbg(hdmi->dev, "[%s] done\n", __FUNCTION__);
mutex_unlock(&work_mutex);
}
\ No newline at end of file
extern const struct fb_videomode hdmi_mode[];
-#define HDMI_DEBUG
+#define hdmi_err(dev, format, arg...) \
+ dev_printk(KERN_ERR , dev , format , ## arg)
#ifdef HDMI_DEBUG
#define hdmi_dbg(dev, format, arg...) \