From: Zheng Yang Date: Tue, 4 Sep 2012 07:08:21 +0000 (+0800) Subject: rk30/rk2928 hdmi: X-Git-Tag: firefly_0821_release~8740 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=39f81f80670f503f50157fd4fb959dc99f072424;p=firefly-linux-kernel-4.4.55.git rk30/rk2928 hdmi: 1. Fix memory leek bug at hdmi_switch_fb(). 2. Add 100ms delay when read edid failed. 3. Delete unused code. 4. rk2928 hdmi support hdcp. --- diff --git a/drivers/video/rockchip/hdmi/Kconfig b/drivers/video/rockchip/hdmi/Kconfig index e3700bbd817d..144b9a51981f 100755 --- a/drivers/video/rockchip/hdmi/Kconfig +++ b/drivers/video/rockchip/hdmi/Kconfig @@ -1,9 +1,22 @@ -menu "RK_HDMI" -config RK_HDMI - bool "RK_HDMI support" +menuconfig RK_HDMI + bool "Rockchip HDMI support" + select FB_MODE_HELPERS if RK_HDMI source "drivers/video/rockchip/hdmi/chips/Kconfig" endif -endmenu +config RK_HDMI_DEBUG + bool "Rockchip HDMI Debugging" + depends on RK_HDMI + default n + help + Enableds verbose debugging the the HDMI drivers + +config RK_HDMI_CTL_CODEC + bool "Mute Codec When HDMI Actived" + depends on RK_HDMI + default n + help + If you say y heres, Codec will be mute when hdmi inserted, + and unmute when removed. diff --git a/drivers/video/rockchip/hdmi/chips/Kconfig b/drivers/video/rockchip/hdmi/chips/Kconfig index e0c1c271bdc1..c01155675dcc 100755 --- a/drivers/video/rockchip/hdmi/chips/Kconfig +++ b/drivers/video/rockchip/hdmi/chips/Kconfig @@ -3,13 +3,11 @@ choice config HDMI_RK30 bool "RK30 HDMI support" depends on LCDC_RK30 - select FB_MODE_HELPERS help Support rk30 hdmi if you say y here config HDMI_RK2928 bool "RK2928 HDMI support" depends on LCDC_RK2928 - select FB_MODE_HELPERS help Support rk2928 hdmi if you say y here endchoice diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/Kconfig b/drivers/video/rockchip/hdmi/chips/rk2928/Kconfig index 8b137891791f..49a9cbf65013 100755 --- a/drivers/video/rockchip/hdmi/chips/rk2928/Kconfig +++ b/drivers/video/rockchip/hdmi/chips/rk2928/Kconfig @@ -1 +1,14 @@ +config HDCP_RK2928 + bool "RK2928 HDCP support" + depends on HDMI_RK2928 + default n + help + HDCP Interface. This adds the High Definition Content Protection Interface. + See http://www.digital-cp.com/ for HDCP specification. +config HDCP_RK2928_DEBUG + bool "RK2928 HDCP Debugging" + depends on HDCP_RK2928 + default n + help + Enableds verbose debugging the the HDCP drivers diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/Makefile b/drivers/video/rockchip/hdmi/chips/rk2928/Makefile index d3227c7f27d9..1e17c7641c67 100755 --- a/drivers/video/rockchip/hdmi/chips/rk2928/Makefile +++ b/drivers/video/rockchip/hdmi/chips/rk2928/Makefile @@ -2,7 +2,8 @@ # Makefile for HDMI linux kernel module. # -ccflags-$(CONFIG_HDMI_RK30_DEBUG) = -DDEBUG -DHDMI_DEBUG +ccflags-$(CONFIG_RK_HDMI_DEBUG) = -DDEBUG -DHDMI_DEBUG +ccflags-$(CONFIG_HDCP_RK2928_DEBUG) = -DHDCP_DEBUG -obj-y += rk2928_hdmi_hw.o rk2928_hdmi.o -obj-$(CONFIG_HDCP_RK2928) += hdcp/ +obj-$(CONFIG_HDMI_RK2928) += rk2928_hdmi_hw.o rk2928_hdmi.o +obj-$(CONFIG_HDCP_RK2928) += rk2928_hdmi_hdcp.o rk2928_hdcp.o diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/Kconfig b/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/Kconfig deleted file mode 100755 index 1bb3c3a24f56..000000000000 --- a/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -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 diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/Makefile b/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/Makefile deleted file mode 100755 index 108b67ca134e..000000000000 --- a/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# 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 diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdcp.c b/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdcp.c deleted file mode 100755 index 68d0ac841a67..000000000000 --- a/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdcp.c +++ /dev/null @@ -1,570 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#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) -{ - int value; - DBG("%s 0x%x", __FUNCTION__, interrupt); - if(interrupt & m_INT_HDCP_ERR) - { - value = HDMIRdReg(HDCP_ERROR); - HDMIWrReg(HDCP_ERROR, value); - printk(KERN_INFO "HDCP: Error 0x%02x\n", value); - - if( (hdcp->hdcp_state != HDCP_DISABLED) && - (hdcp->hdcp_state != HDCP_ENABLE_PENDING) ) - { - hdcp_submit_work(HDCP_FAIL_EVENT, 0); - } - } - else if(interrupt & (m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY)) - hdcp_submit_work(HDCP_KSV_LIST_RDY_EVENT, 0); - else if(interrupt & m_INT_AUTH_DONE) - hdcp_submit_work(HDCP_AUTH_PASS_EVENT, 0); -} - -/*----------------------------------------------------------------------------- - * 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 diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdmi_hdcp.c b/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdmi_hdcp.c deleted file mode 100755 index 1184989a57b2..000000000000 --- a/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdmi_hdcp.c +++ /dev/null @@ -1,157 +0,0 @@ -#include -#include -#include -#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; - } - // Config DDC Clock - temp = (hdmi->tmdsclk/HDCP_DDC_CLK)/4; - HDMIWrReg(DDC_BUS_FREQ_L, temp & 0xFF); - HDMIWrReg(DDC_BUS_FREQ_H, (temp >> 8) & 0xFF); - // Enable HDCP Interrupt - HDMIWrReg(INTR_MASK2, m_INT_HDCP_ERR | m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY | m_INT_AUTH_DONE | m_INT_AUTH_READY); - // Start HDCP - HDMIMskReg(temp, HDCP_CTRL, m_HDCP_AUTH_START | m_HDCP_FRAMED_ENCRYPED, v_HDCP_AUTH_START(1) | v_HDCP_FRAMED_ENCRYPED(0)); - - 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; -} diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdmi_hdcp.h b/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdmi_hdcp.h deleted file mode 100755 index 0224d88ab134..000000000000 --- a/drivers/video/rockchip/hdmi/chips/rk2928/hdcp/rk30_hdmi_hdcp.h +++ /dev/null @@ -1,99 +0,0 @@ -#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 -#define HDCP_DDC_CLK 100000 - -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 diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdcp.c b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdcp.c new file mode 100755 index 000000000000..25ff53203139 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdcp.c @@ -0,0 +1,563 @@ +#include +#include +#include +#include +#include +#include +#include +#include "rk2928_hdmi.h" +#include "rk2928_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; + } + + rk2928_hdcp_disable(); + rk2928_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 = rk2928_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 = rk2928_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) +{ + rk2928_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); + rk2928_hdcp_disable(); + if(event == HDCP_DISABLE_CTL) { + hdcp->hdcp_state = HDCP_DISABLED; + if(hdcp->hdmi_state == HDMI_STARTED) + rk2928_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; + + rk2928_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 rk2928_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 rk2928_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; + } + + rk2928_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 rk2928_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(rk2928_hdcp_init); +module_exit(rk2928_hdcp_exit); diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdcp.h b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdcp.h new file mode 100755 index 000000000000..4d55037e5e5d --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdcp.h @@ -0,0 +1,190 @@ +#ifndef __RK2928_HDCP_H__ +#define __RK2928_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 rk2928_hdcp_disable(void); +extern int rk2928_hdcp_start_authentication(void); +extern int rk2928_hdcp_check_bksv(void); +extern int rk2928_hdcp_load_key2mem(struct hdcp_keys *key); +extern void rk2928_hdcp_interrupt(char *status1, char *status2); +#endif /* __rk2928_HDCP_H__ */ \ No newline at end of file diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.h b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.h index 4695086bf329..9efceb36d63b 100755 --- a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.h +++ b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi.h @@ -3,8 +3,10 @@ #include "../../rk_hdmi.h" +#define HDMI_SOURCE_DEFAULT HDMI_SOURCE_LCDC0 -extern int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void), +extern void rk2928_hdmi_control_output(int enable); +extern int rk2928_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)); diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hdcp.c b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hdcp.c new file mode 100755 index 000000000000..b83daca53d78 --- /dev/null +++ b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hdcp.c @@ -0,0 +1,135 @@ +#include +#include "rk2928_hdmi.h" +#include "rk2928_hdmi_hw.h" +#include "rk2928_hdcp.h" + +#define HDCPWrReg HDMIWrReg +#define HDCPRdReg HDMIRdReg +#define HDCPMskReg(temp, addr, msk, val) \ + temp = HDCPRdReg(addr) & (0xFF - (msk)) ; \ + HDCPWrReg(addr, temp | ( (val) & (msk) )); + +void rk2928_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 rk2928_hdcp_load_key2mem(struct hdcp_keys *key) +{ + int i; + DBG("HDCP: rk2928_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: rk2928_hdcp_load_key2mem end"); + return HDCP_OK; +} + +int rk2928_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); + + temp = HDCPRdReg(HDCP_KEY_STATUS); + while( ( temp & m_KEY_READY) == 0 ) { + if(retry > 10) { + printk(KERN_ERR "HDCP: loaded key error\n"); + return HDCP_KEY_ERR; + } + rk2928_hdcp_load_key2mem(hdcp->keys); + msleep(1); + temp = HDCPRdReg(HDCP_KEY_STATUS); + } + + // 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 rk2928_hdcp_check_bksv(void) +{ + int i, j; + char temp = 0, bksv[5]; + char *invalidkey; + + for(i = 0; i < 5; i++) { + bksv[i] = HDCPRdReg(HDCP_KSV_BYTE0 + (4 - i)) & 0xFF; + } + DBG("bksv is 0x%02x%02x%02x%02x%02x", bksv[0], bksv[1], bksv[2], bksv[3], bksv[4]); + + 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 rk2928_hdcp_interrupt(char *status1, char *status2) +{ + char interrupt1 = HDCPRdReg(HDCP_INT_STATUS1); + char interrupt2 = HDCPRdReg(HDCP_INT_STATUS2); + if(interrupt1) { + HDCPWrReg(HDCP_INT_STATUS1, interrupt1); + if(interrupt1 & m_INT_HDCP_ERR) + printk(KERN_INFO "HDCP: Error 0x%02x\n", HDCPRdReg(HDCP_ERROR)); + } + if(interrupt2) + HDCPWrReg(HDCP_INT_STATUS2, interrupt2); + + *status1 = interrupt1; + *status2 = interrupt2; +} \ No newline at end of file diff --git a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.c b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.c index b5dd18054bff..f2e709db6f04 100755 --- a/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.c +++ b/drivers/video/rockchip/hdmi/chips/rk2928/rk2928_hdmi_hw.c @@ -143,7 +143,9 @@ int rk2928_hdmi_read_edid(int block, unsigned char *buff) break; }else hdmi_err(hdmi->dev, "[%s] edid read error\n", __FUNCTION__); - + + hdmi_dbg(hdmi->dev, "[%s] edid try times %d\n", __FUNCTION__, trytime); + msleep(100); } // Disable edid interrupt HDMIWrReg(INTERRUPT_MASK1, m_INT_HOTPLUG); @@ -366,7 +368,7 @@ static int rk2928_hdmi_config_audio(struct hdmi_audio *audio) return 0; } -static void rk2928_hdmi_control_output(int enable) +void rk2928_hdmi_control_output(int enable) { char mutestatus = 0; @@ -444,7 +446,7 @@ int rk2928_hdmi_initial(void) int rc = HDMI_ERROR_SUCESS; hdmi->pwr_mode = NORMAL; - hdmi->hdmi_removed = rk2928_hdmi_removed ; + hdmi->remove = rk2928_hdmi_removed ; hdmi->control_output = rk2928_hdmi_control_output; hdmi->config_video = rk2928_hdmi_config_video; hdmi->config_audio = rk2928_hdmi_config_audio; diff --git a/drivers/video/rockchip/hdmi/chips/rk30/Kconfig b/drivers/video/rockchip/hdmi/chips/rk30/Kconfig index 31deae4f6526..27edf4102d3d 100755 --- a/drivers/video/rockchip/hdmi/chips/rk30/Kconfig +++ b/drivers/video/rockchip/hdmi/chips/rk30/Kconfig @@ -1,16 +1 @@ -config HDMI_RK30_CTL_CODEC - bool "Mute Codec When HDMI Actived" - depends on HDMI_RK30 - default n - help - If you say y heres, Codec will be mute when hdmi inserted, - and unmute when removed. - -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/chips/rk30/hdcp/Kconfig" \ No newline at end of file diff --git a/drivers/video/rockchip/hdmi/chips/rk30/Makefile b/drivers/video/rockchip/hdmi/chips/rk30/Makefile index 98dfae276674..0704c997140b 100755 --- a/drivers/video/rockchip/hdmi/chips/rk30/Makefile +++ b/drivers/video/rockchip/hdmi/chips/rk30/Makefile @@ -2,7 +2,7 @@ # Makefile for HDMI linux kernel module. # -ccflags-$(CONFIG_HDMI_RK30_DEBUG) = -DDEBUG -DHDMI_DEBUG +ccflags-$(CONFIG_RK_HDMI_DEBUG) = -DDEBUG -DHDMI_DEBUG obj-$(CONFIG_HDMI_RK30) += rk30_hdmi_hw.o rk30_hdmi.o obj-$(CONFIG_HDCP_RK30) += hdcp/ diff --git a/drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi.h b/drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi.h index 4695086bf329..f0220d013447 100755 --- a/drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi.h +++ b/drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi.h @@ -3,6 +3,8 @@ #include "../../rk_hdmi.h" +/* default HDMI video source */ +#define HDMI_SOURCE_DEFAULT HDMI_SOURCE_LCDC1 extern int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void), void (*hdcp_irq_cb)(int status), diff --git a/drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi_hw.c b/drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi_hw.c index 5f1d2662cf23..3e7ed568e684 100755 --- a/drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi_hw.c +++ b/drivers/video/rockchip/hdmi/chips/rk30/rk30_hdmi_hw.c @@ -16,7 +16,7 @@ int rk30_hdmi_initial(void) int rc = HDMI_ERROR_SUCESS; hdmi->pwr_mode = PWR_SAVE_MODE_A; - hdmi->hdmi_removed = rk30_hdmi_removed ; + hdmi->remove = rk30_hdmi_removed ; hdmi->control_output = rk30_hdmi_control_output; hdmi->config_video = rk30_hdmi_config_video; hdmi->config_audio = rk30_hdmi_config_audio; @@ -144,11 +144,12 @@ int rk30_hdmi_read_edid(int block, unsigned char *buff) } if(interrupt & m_INT_EDID_ERR) hdmi_err(hdmi->dev, "[%s] edid read error\n", __FUNCTION__); - + + hdmi_dbg(hdmi->dev, "[%s] edid try times %d\n", __FUNCTION__, trytime); + msleep(100); } // Disable edid interrupt HDMIWrReg(INTR_MASK1, m_INT_HOTPLUG | m_INT_MSENS); -// msleep(100); return ret; } diff --git a/drivers/video/rockchip/hdmi/rk_hdmi.h b/drivers/video/rockchip/hdmi/rk_hdmi.h index 83d3925e482b..7222a8cf33e2 100755 --- a/drivers/video/rockchip/hdmi/rk_hdmi.h +++ b/drivers/video/rockchip/hdmi/rk_hdmi.h @@ -27,12 +27,6 @@ enum { HDMI_SOURCE_LCDC1 = 1 }; -/* default HDMI video source */ -#ifdef CONFIG_ARCH_RK2928 -#define HDMI_SOURCE_DEFAULT HDMI_SOURCE_LCDC0 -#else -#define HDMI_SOURCE_DEFAULT HDMI_SOURCE_LCDC1 -#endif /* If HDMI_ENABLE, system will auto configure output mode according to EDID * If HDMI_DISABLE, system will output mode according to macro HDMI_VIDEO_DEFAULT_MODE */ @@ -244,7 +238,6 @@ struct hdmi_edid { int audio_num; //Device supported audio type number }; -extern const struct fb_videomode hdmi_mode[]; /* RK HDMI Video Configure Parameters */ struct hdmi_video_para { int vic; @@ -253,6 +246,7 @@ struct hdmi_video_para { int output_mode; //output hdmi or dvi int output_color; //output video color mode }; + struct hdmi { struct device *dev; struct clk *hclk; //HDMI AHP clk @@ -296,8 +290,8 @@ struct hdmi { int yscale; // y directoon scale value int tmdsclk; // TDMS Clock frequency - - int (*hdmi_removed)(void); + int (*insert)(void); + int (*remove)(void); void (*control_output)(int enable); int (*config_video)(struct hdmi_video_para *vpara); int (*config_audio)(struct hdmi_audio *audio); @@ -323,8 +317,6 @@ struct hdmi { #endif extern struct hdmi *hdmi; -extern struct hdmi *hdmi_register(int extra); -extern void hdmi_unregister(struct hdmi *hdmi); extern int hdmi_get_hotplug(void); extern int hdmi_set_info(struct rk29fb_screen *screen, unsigned int vic); extern void hdmi_init_lcdc(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info); @@ -338,6 +330,5 @@ extern struct hdmi_video_timing * hdmi_find_mode(int vic); extern int hdmi_find_best_mode(struct hdmi* hdmi, int vic); 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 void hdmi_work(struct work_struct *work); #endif diff --git a/drivers/video/rockchip/hdmi/rk_hdmi_lcdc.c b/drivers/video/rockchip/hdmi/rk_hdmi_lcdc.c index be2be8b72a9e..e212ae7792ad 100755 --- a/drivers/video/rockchip/hdmi/rk_hdmi_lcdc.c +++ b/drivers/video/rockchip/hdmi/rk_hdmi_lcdc.c @@ -8,7 +8,7 @@ #define SWAP_RB 0 #define LCD_ACLK 800000000 -const struct fb_videomode hdmi_mode [] = { +static const struct fb_videomode hdmi_mode [] = { //name refresh xres yres pixclock h_bp h_fp v_bp v_fp h_pw v_pw polariry PorI flag(used for vic) //{ "640x480p@60Hz", 60, 640, 480, 25175000, 48, 16, 33, 10, 96, 2, 0, 0, 1 }, //{ "720x480i@60Hz", 60, 720, 480, 27000000, 114, 38, 15, 4, 124, 3, 0, 1, 6 }, @@ -507,9 +507,12 @@ int hdmi_switch_fb(struct hdmi *hdmi, int vic) rc = hdmi_set_info(screen, hdmi->vic); if(rc == 0) { - rk_fb_switch_screen(screen, 1, HDMI_SOURCE_DEFAULT); - rk_fb_disp_scale(hdmi->xscale, hdmi->yscale, HDMI_SOURCE_DEFAULT); + rk_fb_switch_screen(screen, 1, hdmi->lcdc->id); + rk_fb_disp_scale(hdmi->xscale, hdmi->yscale, hdmi->lcdc->id); } + + kfree(screen); + return rc; } diff --git a/drivers/video/rockchip/hdmi/rk_hdmi_sysfs.c b/drivers/video/rockchip/hdmi/rk_hdmi_sysfs.c index 45d28eea57b5..dc0c5d82fb4f 100755 --- a/drivers/video/rockchip/hdmi/rk_hdmi_sysfs.c +++ b/drivers/video/rockchip/hdmi/rk_hdmi_sysfs.c @@ -112,7 +112,7 @@ static int hdmi_set_scale(struct rk_display_device *device, int direction, int v hdmi->yscale = value; else return -1; - rk_fb_disp_scale(hdmi->xscale, hdmi->yscale, HDMI_SOURCE_DEFAULT); + rk_fb_disp_scale(hdmi->xscale, hdmi->yscale, hdmi->lcdc->id); return 0; } diff --git a/drivers/video/rockchip/hdmi/rk_hdmi_task.c b/drivers/video/rockchip/hdmi/rk_hdmi_task.c index 7bb6eb6c2628..5f34b23236dc 100755 --- a/drivers/video/rockchip/hdmi/rk_hdmi_task.c +++ b/drivers/video/rockchip/hdmi/rk_hdmi_task.c @@ -2,7 +2,7 @@ #include #include "rk_hdmi.h" -#ifdef CONFIG_HDMI_RK30_CTL_CODEC +#ifdef CONFIG_RK_HDMI_CTL_CODEC extern void codec_set_spk(bool on); #endif @@ -80,12 +80,12 @@ void hdmi_sys_remove(void) memset(&hdmi->edid, 0, sizeof(struct hdmi_edid)); INIT_LIST_HEAD(&hdmi->edid.modelist); hdmi->display = HDMI_DISABLE; - rk_fb_switch_screen(hdmi->lcdc->screen1, 0, HDMI_SOURCE_DEFAULT); + rk_fb_switch_screen(hdmi->lcdc->screen1, 0, hdmi->lcdc->id); kobject_uevent_env(&hdmi->dev->kobj, KOBJ_REMOVE, envp); #ifdef CONFIG_SWITCH switch_set_state(&(hdmi->switch_hdmi), 0); #endif - #ifdef CONFIG_HDMI_RK30_CTL_CODEC + #ifdef CONFIG_RK_HDMI_CTL_CODEC codec_set_spk(1); #endif } @@ -96,7 +96,7 @@ static void hdmi_sys_sleep(void) if(hdmi->enable) disable_irq(hdmi->irq); hdmi->state = HDMI_SLEEP; - hdmi->hdmi_removed(); + hdmi->remove(); if(hdmi->enable) enable_irq(hdmi->irq); mutex_unlock(&hdmi->enable_mutex); @@ -121,7 +121,7 @@ static int hdmi_process_command(void) hdmi_sys_remove(); hdmi->state = HDMI_SLEEP; hdmi->hotplug = HDMI_HPD_REMOVED; - hdmi->hdmi_removed(); + hdmi->remove(); state = HDMI_SLEEP; } mutex_unlock(&hdmi->enable_mutex); @@ -183,6 +183,8 @@ void hdmi_work(struct work_struct *work) if(hotplug != hdmi->hotplug) { if(hotplug == HDMI_HPD_ACTIVED){ + if(hdmi->insert) + hdmi->insert(); hdmi->state = READ_PARSE_EDID; } else if(hdmi->hotplug == HDMI_HPD_ACTIVED) { @@ -192,7 +194,7 @@ void hdmi_work(struct work_struct *work) hdmi_sys_sleep(); else { hdmi->state = WAIT_HOTPLUG; - hdmi->hdmi_removed(); + hdmi->remove(); } if(hdmi->wait == 1) { complete(&hdmi->complete); @@ -203,7 +205,7 @@ void hdmi_work(struct work_struct *work) } else if(hotplug == HDMI_HPD_REMOVED) { hdmi->state = HDMI_SLEEP; - hdmi->hdmi_removed(); + hdmi->remove(); } hdmi->hotplug = hotplug; } @@ -224,7 +226,7 @@ void hdmi_work(struct work_struct *work) #ifdef CONFIG_SWITCH switch_set_state(&(hdmi->switch_hdmi), 1); #endif - #ifdef CONFIG_HDMI_RK30_CTL_CODEC + #ifdef CONFIG_RK_HDMI_CTL_CODEC codec_set_spk(0); #endif } @@ -297,15 +299,6 @@ void hdmi_work(struct work_struct *work) }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(); -// -// } -// } hdmi_dbg(hdmi->dev, "[%s] done\n", __FUNCTION__); mutex_unlock(&work_mutex); }