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