From d2f82fa2f0c96628a9f9bc5091ed1d8935a6fa38 Mon Sep 17 00:00:00 2001 From: hjc Date: Mon, 5 Aug 2013 16:30:14 +0800 Subject: [PATCH] rk fb: add rk31xx interface rk_fb_poll_wait_frame_complete for ddr and fps freq --- drivers/video/rockchip/lcdc/rk3066b_lcdc.c | 46 ++++++++++++-- drivers/video/rockchip/lcdc/rk3188_lcdc.c | 64 +++++++++++++++---- drivers/video/rockchip/lcdc/rk3188_lcdc.h | 4 +- drivers/video/rockchip/rk_fb.c | 71 +++++++++++++++++++++- include/linux/rk_fb.h | 12 ++++ 5 files changed, 176 insertions(+), 21 deletions(-) diff --git a/drivers/video/rockchip/lcdc/rk3066b_lcdc.c b/drivers/video/rockchip/lcdc/rk3066b_lcdc.c index bd992f46b7e9..e4d863396ff8 100755 --- a/drivers/video/rockchip/lcdc/rk3066b_lcdc.c +++ b/drivers/video/rockchip/lcdc/rk3066b_lcdc.c @@ -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) diff --git a/drivers/video/rockchip/lcdc/rk3188_lcdc.c b/drivers/video/rockchip/lcdc/rk3188_lcdc.c index c7a6507a93db..e1341bc7382d 100755 --- a/drivers/video/rockchip/lcdc/rk3188_lcdc.c +++ b/drivers/video/rockchip/lcdc/rk3188_lcdc.c @@ -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; } diff --git a/drivers/video/rockchip/lcdc/rk3188_lcdc.h b/drivers/video/rockchip/lcdc/rk3188_lcdc.h index 868d2c0b5c80..c26d8cf96b4c 100755 --- a/drivers/video/rockchip/lcdc/rk3188_lcdc.h +++ b/drivers/video/rockchip/lcdc/rk3188_lcdc.h @@ -183,7 +183,7 @@ #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) @@ -192,7 +192,7 @@ #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) diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index e709ee2491d0..11e10afc7d27 100755 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -29,11 +29,14 @@ #include #include #include -#include +#include #include #include "hdmi/rk_hdmi.h" #include +#include +#include + 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) diff --git a/include/linux/rk_fb.h b/include/linux/rk_fb.h index f5599fec1349..179e9c1cc84a 100755 --- a/include/linux/rk_fb.h +++ b/include/linux/rk_fb.h @@ -62,6 +62,17 @@ #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); -- 2.34.1