rk fb: add rk31xx interface rk_fb_poll_wait_frame_complete for ddr and fps freq
authorhjc <hjc@rock-chips.com>
Mon, 5 Aug 2013 08:30:14 +0000 (16:30 +0800)
committerhjc <hjc@rock-chips.com>
Mon, 5 Aug 2013 08:30:24 +0000 (16:30 +0800)
drivers/video/rockchip/lcdc/rk3066b_lcdc.c
drivers/video/rockchip/lcdc/rk3188_lcdc.c
drivers/video/rockchip/lcdc/rk3188_lcdc.h
drivers/video/rockchip/rk_fb.c
include/linux/rk_fb.h

index bd992f46b7e9085f1b5aed236df019602a470c79..e4d863396ff8dea59953a79018dadc84fa58fda3 100755 (executable)
@@ -706,8 +706,12 @@ int rk3066b_lcdc_pan_display(struct rk_lcdc_device_driver * dev_drv,int layer_id
        if((dev_drv->first_frame))  //this is the first frame of the system ,enable frame start interrupt
        {
                dev_drv->first_frame = 0;
-               LcdMskReg(lcdc_dev,INT_STATUS,m_FRM_STARTCLEAR | m_FRM_STARTMASK ,
-                         v_FRM_STARTCLEAR(1) | v_FRM_STARTMASK(0));
+               LcdMskReg(lcdc_dev,INT_STATUS,m_HOR_STARTMASK | m_FRM_STARTMASK | m_SCANNING_MASK | 
+                       m_HOR_STARTCLEAR | m_FRM_STARTCLEAR |m_SCANNING_CLEAR | m_SCAN_LINE_NUM,
+                         v_HOR_STARTMASK(1) | v_FRM_STARTMASK(0) | v_SCANNING_MASK(0) |
+                         v_HOR_STARTCLEAR(1) | v_FRM_STARTCLEAR(1) | v_SCANNING_CLEAR(1) |
+                         //v_SCANNING_CLEAR(screen->vsync_len + screen->upper_margin+screen->y_res -1));
+                         v_SCAN_LINE_NUM(screen->vsync_len + screen->upper_margin+screen->y_res -1));
                LCDC_REG_CFG_DONE();  // write any value to  REG_CFG_DONE let config become effective
                 
        }
@@ -1120,7 +1124,7 @@ int rk3066b_lcdc_early_resume(struct rk_lcdc_device_driver *dev_drv)
                LcdMskReg(lcdc_dev, INT_STATUS, m_SCANNING_CLEAR | m_FRM_STARTCLEAR | m_HOR_STARTCLEAR |
                                        m_SCANNING_MASK | m_HOR_STARTMASK | m_FRM_STARTMASK , 
                                        v_SCANNING_CLEAR(1) | v_FRM_STARTCLEAR(1) | v_HOR_STARTCLEAR(1) | 
-                                       v_SCANNING_MASK(1) | v_FRM_STARTMASK(0) | v_HOR_STARTMASK(1));
+                                       v_SCANNING_MASK(0) | v_FRM_STARTMASK(0) | v_HOR_STARTMASK(1));
                LCDC_REG_CFG_DONE();
        }
        lcdc_dev->clk_on = 1;
@@ -1137,6 +1141,9 @@ int rk3066b_lcdc_early_resume(struct rk_lcdc_device_driver *dev_drv)
 static irqreturn_t rk3066b_lcdc_isr(int irq, void *dev_id)
 {
        struct rk3066b_lcdc_device *lcdc_dev = (struct rk3066b_lcdc_device *)dev_id;
+
+       u32 int_reg = LcdRdReg(lcdc_dev,INT_STATUS);
+       if(int_reg & m_FRM_START){
        ktime_t timestamp = ktime_get();
        
        LcdMskReg(lcdc_dev, INT_STATUS, m_FRM_STARTCLEAR, v_FRM_STARTCLEAR(1));
@@ -1154,7 +1161,10 @@ static irqreturn_t rk3066b_lcdc_isr(int irq, void *dev_id)
 
        lcdc_dev->driver.vsync_info.timestamp = timestamp;
        wake_up_interruptible_all(&lcdc_dev->driver.vsync_info.wait);
-       
+       }
+       else if(int_reg & m_SCANNING_FLAG){
+               LcdMskReg(lcdc_dev, INT_STATUS, m_FRM_STARTCLEAR, v_SCANNING_CLEAR(1));
+       }
        return IRQ_HANDLED;
 }
 
@@ -1191,6 +1201,33 @@ static int rk3066b_set_dsp_lut(struct rk_lcdc_device_driver *dev_drv,int *lut)
        return ret;
 }
 
+int rk3066b_lcdc_poll_vblank(struct rk_lcdc_device_driver * dev_drv)
+{
+       struct rk3066b_lcdc_device *lcdc_dev = 
+                               container_of(dev_drv,struct rk3066b_lcdc_device,driver);    
+        u32 int_reg ;
+       int ret;
+       //spin_lock(&lcdc_dev->reg_lock);
+       if(lcdc_dev->clk_on)
+       {
+               int_reg = LcdRdReg(lcdc_dev,INT_STATUS);
+               if(int_reg & m_SCANNING_FLAG)
+               {
+                     LcdMskReg(lcdc_dev, INT_STATUS, m_SCANNING_CLEAR,v_SCANNING_CLEAR(1));              
+                     ret =  RK_LF_STATUS_FC;
+               }
+               else
+                    ret = RK_LF_STATUS_FR;
+       }
+       else
+       {
+               ret = RK_LF_STATUS_NC;
+       }       
+       //spin_unlock(&lcdc_dev->reg_lock);
+
+
+       return ret;
+}
 
 static struct layer_par lcdc_layer[] = {
        [0] = {
@@ -1225,6 +1262,7 @@ static struct rk_lcdc_device_driver lcdc_driver = {
        .fb_get_layer           = rk3066b_fb_get_layer,
        .fb_layer_remap         = rk3066b_fb_layer_remap,
        .set_dsp_lut            = rk3066b_set_dsp_lut,
+       .poll_vblank            = rk3066b_lcdc_poll_vblank,
 };
 #ifdef CONFIG_PM
 static int rk3066b_lcdc_suspend(struct platform_device *pdev, pm_message_t state)
index c7a6507a93db70517b07ccf3b5aa25fe12d3ed2a..e1341bc7382dc784cf8bbe2aca9c563d73105ff9 100755 (executable)
@@ -944,8 +944,12 @@ static int rk3188_lcdc_pan_display(struct rk_lcdc_device_driver * dev_drv,int la
        if((dev_drv->first_frame))  //this is the first frame of the system ,enable frame start interrupt
        {
                dev_drv->first_frame = 0;
-               lcdc_msk_reg(lcdc_dev,INT_STATUS,m_FS_INT_CLEAR |m_FS_INT_EN ,
-                         v_FS_INT_CLEAR(1) | v_FS_INT_EN(1));
+               lcdc_msk_reg(lcdc_dev,INT_STATUS,m_HS_INT_CLEAR | m_HS_INT_EN |
+                       m_FS_INT_CLEAR | m_FS_INT_EN | m_LF_INT_EN | m_LF_INT_CLEAR |
+                       m_LF_INT_NUM | m_BUS_ERR_INT_CLEAR | m_BUS_ERR_INT_EN,
+                       v_FS_INT_CLEAR(1) | v_FS_INT_EN(1) | v_HS_INT_CLEAR(1) |
+                       v_HS_INT_EN(0) | v_LF_INT_CLEAR(1) | v_LF_INT_EN(1) |
+                       v_LF_INT_NUM(screen->vsync_len + screen->upper_margin+screen->y_res -1));
                lcdc_cfg_done(lcdc_dev);  // write any value to  REG_CFG_DONE let config become effective
                 
        }
@@ -1425,6 +1429,33 @@ static int rk3188_lcdc_dpi_status(struct rk_lcdc_device_driver *dev_drv)
        return ovl;
 }
 
+int rk3188_lcdc_poll_vblank(struct rk_lcdc_device_driver * dev_drv)
+{
+       struct rk3188_lcdc_device *lcdc_dev = 
+                               container_of(dev_drv,struct rk3188_lcdc_device,driver);    
+        u32 int_reg ;
+       int ret;
+       //spin_lock(&lcdc_dev->reg_lock);
+       if(lcdc_dev->clk_on)
+       {
+               int_reg = lcdc_readl(lcdc_dev,INT_STATUS);
+               if(int_reg & m_LF_INT_STA)
+               {
+                     lcdc_msk_reg(lcdc_dev, INT_STATUS, m_LF_INT_CLEAR,v_LF_INT_CLEAR(1));              
+                     ret =  RK_LF_STATUS_FC;
+               }
+               else
+                    ret = RK_LF_STATUS_FR;
+       }
+       else
+       {
+               ret = RK_LF_STATUS_NC;
+       }       
+       //spin_unlock(&lcdc_dev->reg_lock);
+
+       return ret;
+}
+
 static struct layer_par lcdc_layer[] = {
        [0] = {
                .name           = "win0",
@@ -1459,6 +1490,7 @@ static struct rk_lcdc_device_driver lcdc_driver = {
        .fb_get_layer           = rk3188_fb_get_layer,
        .fb_layer_remap         = rk3188_fb_layer_remap,
        .set_dsp_lut            = rk3188_set_dsp_lut,
+       .poll_vblank            = rk3188_lcdc_poll_vblank,
        .dpi_open               = rk3188_lcdc_dpi_open,
        .dpi_layer_sel          = rk3188_lcdc_dpi_layer_sel,
        .dpi_status             = rk3188_lcdc_dpi_status,
@@ -1469,18 +1501,26 @@ static irqreturn_t rk3188_lcdc_isr(int irq, void *dev_id)
        struct rk3188_lcdc_device *lcdc_dev = 
                                (struct rk3188_lcdc_device *)dev_id;
        ktime_t timestamp = ktime_get();
-       
-       lcdc_msk_reg(lcdc_dev, INT_STATUS, m_FS_INT_CLEAR, v_FS_INT_CLEAR(1));
-
-       if(lcdc_dev->driver.wait_fs)  //three buffer ,no need to wait for sync
+       u32 int_reg = lcdc_readl(lcdc_dev,INT_STATUS);
+                
+       if(int_reg & m_FS_INT_STA)
+       {
+               timestamp = ktime_get();
+               lcdc_msk_reg(lcdc_dev, INT_STATUS, m_FS_INT_CLEAR,v_FS_INT_CLEAR(1));
+               if(lcdc_dev->driver.wait_fs)  //three buffer ,no need to wait for sync
+               {
+                       spin_lock(&(lcdc_dev->driver.cpl_lock));
+                       complete(&(lcdc_dev->driver.frame_done));
+                       spin_unlock(&(lcdc_dev->driver.cpl_lock));
+               }
+               lcdc_dev->driver.vsync_info.timestamp = timestamp;
+               wake_up_interruptible_all(&lcdc_dev->driver.vsync_info.wait);
+               
+       }
+       else if(int_reg & m_LF_INT_STA)
        {
-               spin_lock(&(lcdc_dev->driver.cpl_lock));
-               complete(&(lcdc_dev->driver.frame_done));
-               spin_unlock(&(lcdc_dev->driver.cpl_lock));
+               lcdc_msk_reg(lcdc_dev, INT_STATUS, m_LF_INT_CLEAR,v_LF_INT_CLEAR(1));
        }
-       lcdc_dev->driver.vsync_info.timestamp = timestamp;
-       wake_up_interruptible_all(&lcdc_dev->driver.vsync_info.wait);
-       
        return IRQ_HANDLED;
 }
 
index 868d2c0b5c80719ec7043a82d44b7e9b7cd19e3a..c26d8cf96b4c5940c43b537a645347d666715881 100755 (executable)
 #define m_FS_INT_CLEAR         (1<<9)
 #define m_LF_INT_CLEAR         (1<<10)
 #define m_BUS_ERR_INT_CLEAR    (1<<11)
-#define m_LINE_FLAG_NUM                (0xfff<<12)
+#define m_LF_INT_NUM           (0xfff<<12)
 #define v_HS_INT_EN(x)         (((x)&1)<<4)
 #define v_FS_INT_EN(x)         (((x)&1)<<5)
 #define v_LF_INT_EN(x)         (((x)&1)<<6)
 #define v_FS_INT_CLEAR(x)      (((x)&1)<<9)
 #define v_LF_INT_CLEAR(x)      (((x)&1)<<10)
 #define v_BUS_ERR_INT_CLEAR(x) (((x)&1)<<11)
-#define v_LINE_FLAG_NUM(x)     (((x)&0xfff)<<12)
+#define v_LF_INT_NUM(x)                (((x)&0xfff)<<12)
 
 
 #define ALPHA_CTRL             (0x14)
index e709ee2491d0780ead3998217de998fc7a467a08..11e10afc7d2730962a80ea062939de2b2d4f6253 100755 (executable)
 #include <linux/earlysuspend.h>
 #include <asm/div64.h>
 #include <asm/uaccess.h>
-#include<linux/rk_fb.h>
+#include <linux/rk_fb.h>
 #include <plat/ipp.h>
 #include "hdmi/rk_hdmi.h"
 #include <linux/linux_logo.h>
 
+#include <mach/clock.h>
+#include <linux/clk.h>
+
 void rk29_backlight_set(bool on);
 bool rk29_get_backlight_status(void);
 
@@ -117,9 +120,14 @@ struct rk_lcdc_device_driver * rk_get_lcdc_drv(char *name)
 
 static struct rk_lcdc_device_driver * rk_get_prmry_lcdc_drv(void)
 {
-       struct rk_fb_inf *inf =  platform_get_drvdata(g_fb_pdev);
+       struct rk_fb_inf *inf = NULL; 
        struct rk_lcdc_device_driver *dev_drv = NULL;
        int i = 0;
+
+       if(likely(g_fb_pdev))
+               inf = platform_get_drvdata(g_fb_pdev);
+       else
+               return NULL;
        
        for(i = 0; i < inf->num_lcdc;i++)
        {
@@ -133,12 +141,41 @@ static struct rk_lcdc_device_driver * rk_get_prmry_lcdc_drv(void)
        return dev_drv;
 }
 
+//get one frame time
+int rk_fb_get_prmry_screen_ft(void)
+{
+        struct rk_lcdc_device_driver *dev_drv = rk_get_prmry_lcdc_drv();
+        
+        uint32_t pix_count,ft_us,dclk_mhz;
+
+        if (0 == dev_drv->id)
+                dclk_mhz = clk_get_rate(clk_get(NULL, "dclk_lcdc0"))/(1000*1000);
+        else 
+                dclk_mhz = clk_get_rate(clk_get(NULL, "dclk_lcdc1"))/(1000*1000);
+
+        pix_count = (dev_drv->cur_screen->upper_margin + dev_drv->cur_screen->lower_margin + dev_drv->cur_screen->y_res +dev_drv->cur_screen->vsync_len)*
+        (dev_drv->cur_screen->left_margin + dev_drv->cur_screen->right_margin + dev_drv->cur_screen->x_res + dev_drv->cur_screen->hsync_len);       // one frame time ,(pico seconds)
+        
+        ft_us = pix_count / dclk_mhz;
+
+        if(likely(dev_drv))
+            return ft_us;
+        else
+            return 0;
+
+}
+
 static struct rk_lcdc_device_driver * rk_get_extend_lcdc_drv(void)
 {
-       struct rk_fb_inf *inf =  platform_get_drvdata(g_fb_pdev);
+       struct rk_fb_inf *inf = NULL; 
        struct rk_lcdc_device_driver *dev_drv = NULL;
        int i = 0;
        
+       if(likely(g_fb_pdev))
+               inf = platform_get_drvdata(g_fb_pdev);
+       else
+               return NULL;
+       
        for(i = 0; i < inf->num_lcdc; i++)
        {
                if(inf->lcdc_dev_drv[i]->screen_ctr_info->prop == EXTEND)
@@ -163,6 +200,32 @@ u32 rk_fb_get_prmry_screen_pixclock(void)
        struct rk_lcdc_device_driver *dev_drv = rk_get_prmry_lcdc_drv();
        return dev_drv->pixclock;
 }
+
+int rk_fb_poll_prmry_screen_vblank(void)
+{
+       struct rk_lcdc_device_driver *dev_drv = rk_get_prmry_lcdc_drv();
+       if(likely(dev_drv))
+       {
+               if(dev_drv->poll_vblank)
+                       return dev_drv->poll_vblank(dev_drv);
+               else
+                       return RK_LF_STATUS_NC; 
+       }
+       else
+               return RK_LF_STATUS_NC;
+}
+
+bool rk_fb_poll_wait_frame_complete(void)
+{
+       uint32_t timeout = MAX_TIMEOUT;
+       if(rk_fb_poll_prmry_screen_vblank() == RK_LF_STATUS_NC)
+               return false;
+
+       while( !(rk_fb_poll_prmry_screen_vblank() == RK_LF_STATUS_FR)  &&  --timeout);
+       while( !(rk_fb_poll_prmry_screen_vblank() == RK_LF_STATUS_FC)  &&  --timeout);
+
+       return true;
+}
 static int rk_fb_open(struct fb_info *info,int user)
 {
     struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par;
@@ -1409,6 +1472,8 @@ static int init_lcdc_device_driver(struct rk_lcdc_device_driver *dev_drv,
                dev_drv->lcdc_hdmi_process = def_drv->lcdc_hdmi_process;
        if(def_drv->lcdc_reg_update)
                dev_drv->lcdc_reg_update = def_drv->lcdc_reg_update;
+       if(def_drv->poll_vblank)
+               dev_drv->poll_vblank = def_drv->poll_vblank;
        if(def_drv->dpi_open)
                dev_drv->dpi_open = def_drv->dpi_open;
        if(def_drv->dpi_layer_sel)
index f5599fec13499de8f47beafde984a2e0336711f4..179e9c1cc84a7aca0ff6dfd09ac58384168dd23d 100755 (executable)
 #define RK_FBIOPUT_COLOR_KEY_CFG       0x4626
 
 
+/**rk fb events**/
+#define RK_LF_STATUS_FC                  0xef
+#define RK_LF_STATUS_FR                  0xee
+#define RK_LF_STATUS_NC                  0xfe
+#define MAX_TIMEOUT                     (1600000UL << 6) //>0.64s
+
+
+extern int rk_fb_poll_prmry_screen_vblank(void);
+extern int rk_fb_get_prmry_screen_ft(void);
+extern bool rk_fb_poll_wait_frame_complete(void);
+
 /********************************************************************
 **          display output interface supported by rockchip lcdc                       *
 ********************************************************************/
@@ -280,6 +291,7 @@ struct rk_lcdc_device_driver{
        int (*set_dsp_lut)(struct rk_lcdc_device_driver *dev_drv,int *lut);
        int (*read_dsp_lut)(struct rk_lcdc_device_driver *dev_drv,int *lut);
        int (*lcdc_hdmi_process)(struct rk_lcdc_device_driver *dev_drv,int mode); //some lcdc need to some process in hdmi mode
+       int (*poll_vblank)(struct rk_lcdc_device_driver *dev_drv);
        int (*lcdc_rst)(struct rk_lcdc_device_driver *dev_drv);
        int (*dpi_open)(struct rk_lcdc_device_driver *dev_drv,bool open);
        int (*dpi_layer_sel)(struct rk_lcdc_device_driver *dev_drv,int layer_id);