From: Zheng Yang Date: Mon, 23 Apr 2012 13:57:16 +0000 (+0800) Subject: rk30 hdmi: X-Git-Tag: firefly_0821_release~9332 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=9afcf024968647744533bb720f4cbae0cc59dd58;p=firefly-linux-kernel-4.4.55.git rk30 hdmi: 1. fix sometimes hdmi crash when system wakeup from sleep; 2. fix sometimes hotplug interrupt was disabled when disable EDID interrupt. --- diff --git a/drivers/video/rockchip/hdmi/Kconfig b/drivers/video/rockchip/hdmi/Kconfig index 6eb659b61e41..5a4de87b4f8a 100755 --- a/drivers/video/rockchip/hdmi/Kconfig +++ b/drivers/video/rockchip/hdmi/Kconfig @@ -1,5 +1,5 @@ config HDMI_RK30 - bool "hdmi support" + bool "rk30 hdmi support" depends on LCDC_RK30 select FB_MODE_HELPERS # default y diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi.c b/drivers/video/rockchip/hdmi/rk30_hdmi.c index e9ac6620ae14..6fc842c9be81 100755 --- a/drivers/video/rockchip/hdmi/rk30_hdmi.c +++ b/drivers/video/rockchip/hdmi/rk30_hdmi.c @@ -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); } diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi.h b/drivers/video/rockchip/hdmi/rk30_hdmi.h index c54a63d48644..d39c4b0db8f2 100755 --- a/drivers/video/rockchip/hdmi/rk30_hdmi.h +++ b/drivers/video/rockchip/hdmi/rk30_hdmi.h @@ -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; diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi_hw.c b/drivers/video/rockchip/hdmi/rk30_hdmi_hw.c index cd29dbc6f30d..6ce3f62f82d7 100755 --- a/drivers/video/rockchip/hdmi/rk30_hdmi_hw.c +++ b/drivers/video/rockchip/hdmi/rk30_hdmi_hw.c @@ -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)); } } diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi_task.c b/drivers/video/rockchip/hdmi/rk30_hdmi_task.c index 51439e0dba77..6a45a11a3bb1 100755 --- a/drivers/video/rockchip/hdmi/rk30_hdmi_task.c +++ b/drivers/video/rockchip/hdmi/rk30_hdmi_task.c @@ -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); + return; } - if(hdmi->wait == 1) { - complete(&hdmi->complete); - hdmi->wait = 0; + else if(hotplug == HDMI_HPD_REMOVED) { + hdmi->state = HDMI_SLEEP; + rk30_hdmi_removed(); } - return; - } - else if(hotplug != hdmi->hotplug) { - hdmi->hotplug = hotplug; - hdmi->state = READ_PARSE_EDID; } + 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__); } \ No newline at end of file diff --git a/drivers/video/rockchip/hdmi/rk_hdmi.h b/drivers/video/rockchip/hdmi/rk_hdmi.h index 7e77eb8a08b9..5fa293142fbd 100755 --- a/drivers/video/rockchip/hdmi/rk_hdmi.h +++ b/drivers/video/rockchip/hdmi/rk_hdmi.h @@ -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 */