rk30 hdmi:
authorZheng Yang <zhengyang@rock-chips.com>
Mon, 23 Apr 2012 13:57:16 +0000 (21:57 +0800)
committerZheng Yang <zhengyang@rock-chips.com>
Mon, 23 Apr 2012 13:57:16 +0000 (21:57 +0800)
1. fix sometimes hdmi crash when system wakeup from sleep;
2. fix sometimes hotplug interrupt was disabled when disable EDID interrupt.

drivers/video/rockchip/hdmi/Kconfig
drivers/video/rockchip/hdmi/rk30_hdmi.c
drivers/video/rockchip/hdmi/rk30_hdmi.h
drivers/video/rockchip/hdmi/rk30_hdmi_hw.c
drivers/video/rockchip/hdmi/rk30_hdmi_task.c
drivers/video/rockchip/hdmi/rk_hdmi.h

index 6eb659b61e41a2d0ae895ad4afd364b0f2015bd1..5a4de87b4f8a2371ba7d1e7c3e83d34261ef0c6d 100755 (executable)
@@ -1,5 +1,5 @@
 config HDMI_RK30
-        bool "hdmi support"
+        bool "rk30 hdmi support"
         depends on LCDC_RK30
         select FB_MODE_HELPERS
 #        default y
index e9ac6620ae1448334e0fe17cf90cea7034f360fb..6fc842c9be81ad89456f9683577b4c9e0866dd9d 100755 (executable)
@@ -29,7 +29,7 @@ extern void hdmi_register_display_sysfs(struct hdmi *hdmi, struct device *parent
 #ifdef CONFIG_HAS_EARLYSUSPEND\r
 static void hdmi_early_suspend(struct early_suspend *h)\r
 {\r
-       hdmi_dbg(hdmi->dev, "hdmi enter early suspend\n");\r
+       hdmi_dbg(hdmi->dev, "hdmi enter early suspend pwr %d state %d\n", hdmi->pwr_mode, hdmi->state);\r
        disable_irq(hdmi->irq);\r
        hdmi->enable = 0;\r
        hdmi->command = HDMI_CONFIG_ENABLE;\r
@@ -71,7 +71,7 @@ static inline void hdmi_io_remap(void)
        value = (HDMI_SOURCE_DEFAULT << 14) | (1 << 30);\r
        writel(value, GRF_SOC_CON0 + RK30_GRF_BASE);\r
        \r
-       // internal hclk = hdmi_hclk/32\r
+       // internal hclk = hdmi_hclk/20\r
        HDMIWrReg(0x800, 19);\r
 }\r
 \r
index c54a63d486441a8fb3f715a388c56d2d5c7def8d..d39c4b0db8f23a1cf9429aab59e83a8d22226bfb 100755 (executable)
@@ -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;
index cd29dbc6f30d44f9297d29f3c0f18b8958c16a98..6ce3f62f82d78dd45ee0443b7239abb30e4d9ee4 100755 (executable)
@@ -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));
                }
        }
index 51439e0dba77af93f1aa88d9c87bff8b5a910e2d..6a45a11a3bb14c4f4200af0c3e198c0c3e939ec8 100755 (executable)
@@ -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
index 7e77eb8a08b9819dc78b1ec32584f8264fd493d7..5fa293142fbde528c26d3b614c6f9a7c3260d9dd 100755 (executable)
@@ -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 */