rk30: hdmi sometimes read edid failed, fix it.
authorZheng Yang <zhengyang@rock-chips.com>
Thu, 5 Apr 2012 10:20:03 +0000 (18:20 +0800)
committerZheng Yang <zhengyang@rock-chips.com>
Thu, 5 Apr 2012 10:20:03 +0000 (18:20 +0800)
drivers/video/rockchip/hdmi/rk30_hdmi_hw.c
drivers/video/rockchip/hdmi/rk30_hdmi_task.c

index e0200dfacc088f875a6788d31853e21e1a4a21f6..55fce5aed0ce5524f1cec6b3cf5c20a86dd96e30 100755 (executable)
@@ -4,7 +4,7 @@
 #include "rk30_hdmi.h"
 #include "rk30_hdmi_hw.h"
 
-static char interrupt1 = 0, interrupt2 = 0, interrupt3 = 0, interrupt4 = 0;
+static char edid_result = 0;
 
 static inline void delay100us(void)
 {
@@ -61,13 +61,15 @@ 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);
-
-       //Before Phy parameter was set, DDC_CLK is equal to PLLA freq which is 30MHz.
+//     disable_irq(hdmi->irq);
+       spin_lock(&hdmi->irq_lock);
+       edid_result = 0;
+       spin_unlock(&hdmi->irq_lock);
+       //Before Phy parameter was set, DDC_CLK is equal to PLLA freq which is 24MHz.
        //Set DDC I2C CLK which devided from DDC_CLK to 100KHz.
-       ddc_bus_freq = (30000000/HDMI_EDID_DDC_CLK)/4;
+       ddc_bus_freq = (24000000/HDMI_EDID_DDC_CLK)/4;
        HDMIWrReg(DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF);
-       HDMIWrReg(DDC_BUS_FREQ_L, (ddc_bus_freq >> 8) & 0xFF);
-       msleep(10);
+       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));
@@ -81,14 +83,12 @@ int rk30_hdmi_read_edid(int block, unsigned char *buff)
                while(value--)
                {
                        spin_lock(&hdmi->irq_lock);
-                       interrupt = interrupt1;
+                       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))
-                       {
-                               interrupt1 &= ~(m_INT_EDID_ERR | m_INT_EDID_READY);
                                break;
-                       }
                        msleep(10);
                }
                hdmi_dbg(hdmi->dev, "[%s] edid read value %d\n", __FUNCTION__, value);
@@ -114,7 +114,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);
-
+       msleep(100);
+//     enable_irq(hdmi->irq);
        return ret;
 }
 
@@ -426,10 +427,11 @@ int rk30_hdmi_removed(void)
 }
 
 
-
-
 irqreturn_t hdmi_irq(int irq, void *priv)
 {              
+       char interrupt1 = 0, interrupt2 = 0, interrupt3 = 0, interrupt4 = 0;
+       
+       spin_lock(&hdmi->irq_lock);
        if(hdmi->pwr_mode == PWR_SAVE_MODE_A)
        {
                hdmi_dbg(hdmi->dev, "hdmi irq wake up\n");
@@ -438,15 +440,12 @@ 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(hdmi->state == HDMI_SLEEP)
-                               hdmi->state = WAIT_HOTPLUG;                     
+               if((rk30_hdmi_detect_hotplug() == HDMI_HPD_INSERT)) {                   
                        queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10));
                }
        }
        else
        {
-               spin_lock(&hdmi->irq_lock);
                interrupt1 = HDMIRdReg(INTR_STATUS1);
                interrupt2 = HDMIRdReg(INTR_STATUS2);
                interrupt3 = HDMIRdReg(INTR_STATUS3);
@@ -455,7 +454,7 @@ irqreturn_t hdmi_irq(int irq, void *priv)
                HDMIWrReg(INTR_STATUS2, interrupt2);
                HDMIWrReg(INTR_STATUS3, interrupt3);
                HDMIWrReg(INTR_STATUS4, interrupt4);
-#if 1
+#if 0
                hdmi_dbg(hdmi->dev, "[%s] interrupt1 %02x interrupt2 %02x interrupt3 %02x interrupt4 %02x\n",\
                         __FUNCTION__, interrupt1, interrupt2, interrupt3, interrupt4);
 #endif
@@ -466,13 +465,15 @@ irqreturn_t hdmi_irq(int irq, void *priv)
                        interrupt1 &= ~(m_INT_HOTPLUG | m_INT_MSENS);
                        queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10));   
                }
+               else if(interrupt1 & (m_INT_EDID_READY | m_INT_EDID_ERR))
+                       edid_result = interrupt1;
                else if(hdmi->state == HDMI_SLEEP) {
                        hdmi_dbg(hdmi->dev, "hdmi return to sleep mode\n");
                        HDMIWrReg(SYS_CTRL, 0x10);
                        hdmi->pwr_mode = PWR_SAVE_MODE_A;
                }
-               spin_unlock(&hdmi->irq_lock);
        }
+       spin_unlock(&hdmi->irq_lock);
        return IRQ_HANDLED;
 }
 
index 27b627081f1eedc1a48cc490e335747bb18f9b59..f2c23aa826f21158cb600ea29371d8d9955b484f 100755 (executable)
@@ -124,16 +124,17 @@ static int hdmi_process_command(void)
                                break;
                }
        }
-       
+       else if(state == HDMI_SLEEP)
+               state = WAIT_HOTPLUG;
        return state;
 }
 
 void hdmi_work(struct work_struct *work)
 {
-       int hotplug, state_last, state;
+       int hotplug, state_last;
        int rc = HDMI_ERROR_SUCESS, trytimes = 0;
        /* Process hdmi command */
-       state = hdmi_process_command();
+       hdmi->state = hdmi_process_command();
        
        if(!hdmi->enable)
                return;
@@ -144,7 +145,7 @@ void hdmi_work(struct work_struct *work)
        {
                hdmi->hotplug  = hotplug;
                if(hdmi->hotplug  == HDMI_HPD_INSERT)
-                       state = READ_PARSE_EDID;
+                       hdmi->state = READ_PARSE_EDID;
                else {
                        hdmi_sys_remove();
                        kobject_uevent_env(&hdmi->dev->kobj, KOBJ_REMOVE, envp);
@@ -152,14 +153,14 @@ void hdmi_work(struct work_struct *work)
                }                       
        }
        do {
-               state_last = state;
-               switch(state)
+               state_last = hdmi->state;
+               switch(hdmi->state)
                {
                        case READ_PARSE_EDID:
                                rc = hdmi_sys_parse_edid(hdmi);
                                if(rc == HDMI_ERROR_SUCESS)
                                {
-                                       state = SYSTEM_CONFIG;  
+                                       hdmi->state = SYSTEM_CONFIG;    
                                        kobject_uevent_env(&hdmi->dev->kobj, KOBJ_ADD, envp);
                                }
                                break;
@@ -170,23 +171,23 @@ void hdmi_work(struct work_struct *work)
                                        hdmi->vic = hdmi_find_best_mode(hdmi, hdmi->vic);
                                rc = hdmi_switch_fb(hdmi, hdmi->vic);
                                if(rc == HDMI_ERROR_SUCESS)
-                                       state = CONFIG_VIDEO;
+                                       hdmi->state = CONFIG_VIDEO;
                                break;
                        case CONFIG_VIDEO:                                      
                                rc = rk30_hdmi_config_video(hdmi->vic, VIDEO_OUTPUT_RGB444, hdmi->edid.sink_hdmi);                      
                                if(rc == HDMI_ERROR_SUCESS)
                                {
                                        if(hdmi->edid.sink_hdmi)
-                                               state = CONFIG_AUDIO;
+                                               hdmi->state = CONFIG_AUDIO;
                                        else
-                                               state = PLAY_BACK;
+                                               hdmi->state = PLAY_BACK;
                                }
                                break;
                        case CONFIG_AUDIO:
                                rc = rk30_hdmi_config_audio(&(hdmi->audio));
                                                        
                                if(rc == HDMI_ERROR_SUCESS)
-                                       state = PLAY_BACK;
+                                       hdmi->state = PLAY_BACK;
                                break;
                        case PLAY_BACK:
                                rk30_hdmi_control_output(1);
@@ -203,16 +204,15 @@ void hdmi_work(struct work_struct *work)
                        trytimes++;
                        msleep(10);
                }
-               if(state != state_last)
+               if(hdmi->state != state_last) 
                        trytimes = 0;
                
-               hdmi_sys_show_state(state);
-       }while((state != state_last || (rc != HDMI_ERROR_SUCESS) ) && trytimes < HDMI_MAX_TRY_TIMES);
+               hdmi_sys_show_state(hdmi->state);
+       }while((hdmi->state != state_last || (rc != HDMI_ERROR_SUCESS) ) && trytimes < HDMI_MAX_TRY_TIMES);
        
        if(trytimes == HDMI_MAX_TRY_TIMES)
        {
                if(hdmi->hotplug)
                        hdmi_sys_remove();
        }
-       hdmi->state = state;
 }
\ No newline at end of file