rk30 hdmi:

1. fix sometimes hdmi crash when system wakeup from sleep;
	2. fix sometimes hotplug interrupt was disabled when disable EDID interrupt.
This commit is contained in:
Zheng Yang
2012-04-23 21:57:16 +08:00
parent 42e859b4aa
commit 9afcf02496
6 changed files with 70 additions and 33 deletions

View File

@@ -1,5 +1,5 @@
config HDMI_RK30
bool "hdmi support"
bool "rk30 hdmi support"
depends on LCDC_RK30
select FB_MODE_HELPERS
# default y

View File

@@ -29,7 +29,7 @@ extern void hdmi_register_display_sysfs(struct hdmi *hdmi, struct device *parent
#ifdef CONFIG_HAS_EARLYSUSPEND
static void hdmi_early_suspend(struct early_suspend *h)
{
hdmi_dbg(hdmi->dev, "hdmi enter early suspend\n");
hdmi_dbg(hdmi->dev, "hdmi enter early suspend pwr %d state %d\n", hdmi->pwr_mode, hdmi->state);
disable_irq(hdmi->irq);
hdmi->enable = 0;
hdmi->command = HDMI_CONFIG_ENABLE;
@@ -71,7 +71,7 @@ static inline void hdmi_io_remap(void)
value = (HDMI_SOURCE_DEFAULT << 14) | (1 << 30);
writel(value, GRF_SOC_CON0 + RK30_GRF_BASE);
// internal hclk = hdmi_hclk/32
// internal hclk = hdmi_hclk/20
HDMIWrReg(0x800, 19);
}

View File

@@ -65,7 +65,7 @@ struct hdmi {
int state; // hdmi state machine status
int autoconfig; // if true, auto config hdmi output mode according to EDID.
int command; // HDMI configuration command
int display; // HDMI display status
};
extern struct hdmi *hdmi;

View File

@@ -39,7 +39,8 @@ static void rk30_hdmi_set_pwr_mode(int mode)
break;
}
hdmi->pwr_mode = mode;
msleep(10);
if(mode != PWR_SAVE_MODE_A)
msleep(10);
hdmi_dbg(hdmi->dev, "[%s] curmode %02x\n", __FUNCTION__, HDMIRdReg(SYS_CTRL));
}
@@ -48,7 +49,10 @@ int rk30_hdmi_detect_hotplug(void)
int value = HDMIRdReg(HPD_MENS_STA);
hdmi_dbg(hdmi->dev, "[%s] value %02x\n", __FUNCTION__, value);
if( (value & (m_HOTPLUG_STATUS | m_MSEN_STATUS)) == (m_HOTPLUG_STATUS | m_MSEN_STATUS) )
value &= m_HOTPLUG_STATUS | m_MSEN_STATUS;
if(value == (m_HOTPLUG_STATUS | m_MSEN_STATUS) )
return HDMI_HPD_ACTIVED;
else if(value)
return HDMI_HPD_INSERT;
else
return HDMI_HPD_REMOVED;
@@ -61,7 +65,6 @@ int rk30_hdmi_read_edid(int block, unsigned char *buff)
char interrupt = 0, trytime = 2;
hdmi_dbg(hdmi->dev, "[%s] block %d\n", __FUNCTION__, block);
// disable_irq(hdmi->irq);
spin_lock(&hdmi->irq_lock);
edid_result = 0;
spin_unlock(&hdmi->irq_lock);
@@ -72,8 +75,8 @@ int rk30_hdmi_read_edid(int block, unsigned char *buff)
HDMIWrReg(DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF);
// Enable edid interrupt
HDMIMskReg(value, INTR_MASK1, (m_INT_EDID_ERR | m_INT_EDID_READY), (m_INT_EDID_ERR | m_INT_EDID_READY));
HDMIWrReg(INTR_MASK1, m_INT_HOTPLUG | m_INT_MSENS | m_INT_EDID_ERR | m_INT_EDID_READY);
while(trytime--) {
// Config EDID block and segment addr
HDMIWrReg(EDID_WORD_ADDR, (block%2) * 0x80);
@@ -84,7 +87,6 @@ int rk30_hdmi_read_edid(int block, unsigned char *buff)
{
spin_lock(&hdmi->irq_lock);
interrupt = edid_result;
// interrupt = HDMIRdReg(INTR_STATUS1);
spin_unlock(&hdmi->irq_lock);
// hdmi_dbg(hdmi->dev, "[%s] interrupt %02x value %d\n", __FUNCTION__, interrupt, value);
if(interrupt & (m_INT_EDID_ERR | m_INT_EDID_READY))
@@ -113,9 +115,8 @@ int rk30_hdmi_read_edid(int block, unsigned char *buff)
}
// Disable edid interrupt
HDMIMskReg(value, INTR_MASK1, (m_INT_EDID_ERR|m_INT_EDID_READY), 0);
HDMIWrReg(INTR_MASK1, m_INT_HOTPLUG | m_INT_MSENS);
msleep(100);
// enable_irq(hdmi->irq);
return ret;
}
@@ -130,7 +131,6 @@ static inline void rk30_hdmi_config_phy_reg(int reg, int value)
static void rk30_hdmi_config_phy(unsigned char vic)
{
hdmi_dbg(hdmi->dev, "[%s] line %d\n", __FUNCTION__, __LINE__);
HDMIWrReg(DEEP_COLOR_MODE, 0x22); // tmds frequency same as input dlck
rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_B);
switch(vic)
@@ -436,7 +436,7 @@ int rk30_hdmi_removed(void)
}
if(hdmi->pwr_mode == PWR_SAVE_MODE_D)
rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_B);
if(hdmi->pwr_mode == PWR_SAVE_MODE_B)
if(hdmi->pwr_mode == PWR_SAVE_MODE_B && hdmi->state == HDMI_SLEEP)
{
HDMIWrReg(INTR_MASK1, m_INT_HOTPLUG | m_INT_MSENS);
HDMIWrReg(INTR_MASK2, 0);
@@ -461,7 +461,7 @@ irqreturn_t hdmi_irq(int irq, void *priv)
// HDMI was inserted when system is sleeping, irq was triggered only once
// when wake up. So we need to check hotplug status.
if((rk30_hdmi_detect_hotplug() == HDMI_HPD_INSERT)) {
if(HDMIRdReg(HPD_MENS_STA) & (m_HOTPLUG_STATUS | m_MSEN_STATUS)) {
queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10));
}
}

View File

@@ -12,6 +12,9 @@ static void hdmi_sys_show_state(int state)
{
switch(state)
{
case HDMI_SLEEP:
dev_printk(KERN_INFO, hdmi->dev, "HDMI_SLEEP\n");
break;
case HDMI_INITIAL:
dev_printk(KERN_INFO, hdmi->dev, "HDMI_INITIAL\n");
break;
@@ -37,7 +40,7 @@ static void hdmi_sys_show_state(int state)
dev_printk(KERN_INFO, hdmi->dev, "PLAY_BACK\n");
break;
default:
dev_printk(KERN_INFO, hdmi->dev, "Unkown State\n");
dev_printk(KERN_INFO, hdmi->dev, "Unkown State %d\n", state);
break;
}
}
@@ -49,6 +52,7 @@ int hdmi_sys_init(void)
hdmi->state = HDMI_SLEEP;
hdmi->enable = HDMI_ENABLE;
hdmi->autoconfig = HDMI_AUTO_CONFIGURE;
hdmi->display = HDMI_DISABLE;
hdmi->vic = HDMI_VIDEO_DEFAULT_MODE;
hdmi->audio.channel = HDMI_AUDIO_DEFAULT_CHANNEL;
@@ -62,7 +66,6 @@ int hdmi_sys_init(void)
void hdmi_sys_remove(void)
{
rk30_hdmi_removed();
fb_destroy_modelist(&hdmi->edid.modelist);
if(hdmi->edid.audio)
kfree(hdmi->edid.audio);
@@ -74,8 +77,17 @@ void hdmi_sys_remove(void)
}
memset(&hdmi->edid, 0, sizeof(struct hdmi_edid));
INIT_LIST_HEAD(&hdmi->edid.modelist);
hdmi->display = HDMI_DISABLE;
}
static void hdmi_sys_sleep(void)
{
if(hdmi->enable)
disable_irq(hdmi->irq);
hdmi->state = HDMI_SLEEP;
hdmi->hotplug = HDMI_HPD_REMOVED;
rk30_hdmi_removed();
if(hdmi->enable)
enable_irq(hdmi->irq);
}
static int hdmi_process_command(void)
@@ -94,6 +106,9 @@ static int hdmi_process_command(void)
{
if(hdmi->hotplug)
hdmi_sys_remove();
hdmi->state = HDMI_SLEEP;
hdmi->hotplug = HDMI_HPD_REMOVED;
rk30_hdmi_removed();
state = HDMI_SLEEP;
}
if(hdmi->wait == 1) {
@@ -145,22 +160,35 @@ void hdmi_work(struct work_struct *work)
hotplug = rk30_hdmi_detect_hotplug();
hdmi_dbg(hdmi->dev, "[%s] hotplug %02x curvalue %d\n", __FUNCTION__, hotplug, hdmi->hotplug);
if(hotplug == HDMI_HPD_REMOVED) {
hdmi_sys_remove();
if(hotplug != hdmi->hotplug) {
if(hotplug != hdmi->hotplug)
{
if(hotplug == HDMI_HPD_ACTIVED){
hdmi->hotplug = hotplug;
hdmi->state = READ_PARSE_EDID;
}
else if(hdmi->hotplug == HDMI_HPD_ACTIVED) {
hdmi_sys_remove();
hdmi->hotplug = hotplug;
if(hotplug == HDMI_HPD_REMOVED)
hdmi_sys_sleep();
else {
hdmi->state = WAIT_HOTPLUG;
rk30_hdmi_removed();
}
if(hdmi->wait == 1) {
complete(&hdmi->complete);
hdmi->wait = 0;
}
kobject_uevent_env(&hdmi->dev->kobj, KOBJ_REMOVE, envp);
}
if(hdmi->wait == 1) {
complete(&hdmi->complete);
hdmi->wait = 0;
}
return;
}
else if(hotplug != hdmi->hotplug) {
hdmi->hotplug = hotplug;
hdmi->state = READ_PARSE_EDID;
}
else if(hotplug == HDMI_HPD_REMOVED) {
hdmi->state = HDMI_SLEEP;
rk30_hdmi_removed();
}
}
else if(hotplug == HDMI_HPD_REMOVED)
hdmi_sys_sleep();
do {
state_last = hdmi->state;
@@ -200,7 +228,10 @@ void hdmi_work(struct work_struct *work)
hdmi->state = PLAY_BACK;
break;
case PLAY_BACK:
rk30_hdmi_control_output(1);
if(hdmi->display != HDMI_ENABLE) {
rk30_hdmi_control_output(HDMI_ENABLE);
hdmi->display = HDMI_ENABLE;
}
if(hdmi->wait == 1) {
complete(&hdmi->complete);
hdmi->wait = 0;
@@ -222,7 +253,12 @@ void hdmi_work(struct work_struct *work)
if(trytimes == HDMI_MAX_TRY_TIMES)
{
if(hdmi->hotplug)
if(hdmi->hotplug) {
hdmi_sys_remove();
hdmi->hotplug = HDMI_HPD_REMOVED;
hdmi_sys_sleep();
}
}
hdmi_dbg(hdmi->dev, "[%s] done\n", __FUNCTION__);
}

View File

@@ -148,7 +148,8 @@ enum hdmi_change {
// HDMI Hotplug status
enum {
HDMI_HPD_REMOVED = 0,
HDMI_HPD_INSERT
HDMI_HPD_INSERT,
HDMI_HPD_ACTIVED
};
/* HDMI STATUS */