From 61116412690b7e9e64cbe277b5cb2e2a4ab71f7f Mon Sep 17 00:00:00 2001 From: yxj Date: Sun, 19 May 2013 15:43:41 +0800 Subject: [PATCH] mfd:rk616:modify some operation for vif --- drivers/mfd/rk616-core.c | 66 +++++- drivers/mfd/rk616-vif.c | 220 ++++++++++++------ .../video/display/transmitter/rk616_lvds.c | 1 + drivers/video/rockchip/hdmi/rk_hdmi_lcdc.c | 7 +- drivers/video/rockchip/hdmi/rk_hdmi_task.c | 1 + include/linux/mfd/rk616.h | 6 +- 6 files changed, 220 insertions(+), 81 deletions(-) diff --git a/drivers/mfd/rk616-core.c b/drivers/mfd/rk616-core.c index bdcce422588a..40b8d0214410 100644 --- a/drivers/mfd/rk616-core.c +++ b/drivers/mfd/rk616-core.c @@ -91,7 +91,6 @@ static int rk616_i2c_write_reg(struct mfd_rk616 *rk616, u16 reg,u32 *pval) ret = i2c_transfer(adap, &msg, 1); kfree(tx_buf); - return (ret == 1) ? 4 : ret; } @@ -260,6 +259,31 @@ static int rk616_pll_wait_lock(struct mfd_rk616 *rk616,int id) } + +int rk616_pll_pwr_down(struct mfd_rk616 *rk616,int id) +{ + u32 val = 0; + int ret; + int offset; + if(id == 0) //PLL0 + { + offset = 0; + } + else // PLL1 + { + offset = 0x0c; + } + + + val = PLL0_PWR_DN | (PLL0_PWR_DN << 16); + ret = rk616->write_dev(rk616,CRU_PLL0_CON1 + offset,&val); + + return 0; + +} + + + int rk616_pll_set_rate(struct mfd_rk616 *rk616,int id,u32 cfg_val,u32 frac) { u32 val = 0; @@ -273,19 +297,39 @@ int rk616_pll_set_rate(struct mfd_rk616 *rk616,int id,u32 cfg_val,u32 frac) u32 postdiv2 = (con1 >> 6) & 0x7; u8 mode = !frac; - if(id == 0) //PLL0 { + if(((rk616->pll0_rate >> 32) == cfg_val) && + ((rk616->pll0_rate & 0xffffffff) == frac)) + { + //return 0; + } + rk616->pll0_rate = ((u64)cfg_val << 32) | frac; offset = 0; } else // PLL1 { + if(((rk616->pll1_rate >> 32) == cfg_val) && + ((rk616->pll1_rate & 0xffffffff) == frac)) + { + // return 0; + } + rk616->pll1_rate = ((u64)cfg_val << 32) | frac; offset = 0x0c; } val = PLL0_PWR_DN | (PLL0_PWR_DN << 16); ret = rk616->write_dev(rk616,CRU_PLL0_CON1 + offset,&val); + + + ret = rk616->read_dev(rk616,CRU_PLL0_CON2 + offset,&val); + val &= 0xff000000; + if(frac) + val |= PLL0_FRAC(frac); + else + val |= 0x800000; //default value + ret = rk616->write_dev(rk616,CRU_PLL0_CON2 + offset,&val); val = PLL0_POSTDIV1(postdiv1) | PLL0_FBDIV(fbdiv) | PLL0_POSTDIV1_MASK | PLL0_FBDIV_MASK | (PLL0_BYPASS << 16); @@ -294,14 +338,14 @@ int rk616_pll_set_rate(struct mfd_rk616 *rk616,int id,u32 cfg_val,u32 frac) val = PLL0_DIV_MODE(mode) | PLL0_POSTDIV2(postdiv2) | PLL0_REFDIV(refdiv) | (PLL0_DIV_MODE_MASK) | PLL0_POSTDIV2_MASK | PLL0_REFDIV_MASK; ret = rk616->write_dev(rk616,CRU_PLL0_CON1 + offset,&val); - - val = PLL0_FRAC(frac); - ret = rk616->write_dev(rk616,CRU_PLL0_CON2 + offset,&val); val = (PLL0_PWR_DN << 16); ret = rk616->write_dev(rk616,CRU_PLL0_CON1 + offset,&val); + rk616_pll_wait_lock(rk616,id); + msleep(5); + return 0; } @@ -331,9 +375,12 @@ static int rk616_clk_common_init(struct mfd_rk616 *rk616) val = (PLL0_BYPASS) | (PLL0_BYPASS << 16); //bypass pll0 ret = rk616->write_dev(rk616,CRU_PLL0_CON0,&val); + val = PLL0_PWR_DN | (PLL0_PWR_DN << 16); + ret = rk616->write_dev(rk616,CRU_PLL0_CON1,&val); //power down pll0 val = (PLL1_BYPASS) | (PLL1_BYPASS << 16); ret = rk616->write_dev(rk616,CRU_PLL1_CON0,&val); + return 0; } @@ -419,6 +466,14 @@ static int __devexit rk616_i2c_remove(struct i2c_client *client) return 0; } +static void rk616_core_shutdown(struct i2c_client *client) +{ + struct mfd_rk616 *rk616 = i2c_get_clientdata(client); + if(rk616->pdata->power_deinit) + rk616->pdata->power_deinit(); +} + + static const struct i2c_device_id id_table[] = { {"rk616", 0 }, { } @@ -431,6 +486,7 @@ static struct i2c_driver rk616_i2c_driver = { }, .probe = &rk616_i2c_probe, .remove = &rk616_i2c_remove, + .shutdown = &rk616_core_shutdown, .id_table = id_table, }; diff --git a/drivers/mfd/rk616-vif.c b/drivers/mfd/rk616-vif.c index 5a5c847a169e..877c6b761c1a 100644 --- a/drivers/mfd/rk616-vif.c +++ b/drivers/mfd/rk616-vif.c @@ -6,8 +6,123 @@ extern int rk616_pll_set_rate(struct mfd_rk616 *rk616,int id,u32 cfg_val,u32 frac); +extern int rk616_pll_pwr_down(struct mfd_rk616 *rk616,int id); + /*rk616 video interface config*/ + + int rk616_vif_disable(struct mfd_rk616 *rk616,int id) +{ + u32 val = 0; + int ret = 0; + + if(id == 0) //video interface 0 + { + val = (VIF0_EN << 16); //disable vif0 + ret = rk616->write_dev(rk616,VIF0_REG0,&val); + + } + else //vide0 interface 1 + { + val = (VIF0_EN << 16); //disabl VIF1 + ret = rk616->write_dev(rk616,VIF1_REG0,&val); + + } + + msleep(21); + + if(id == 0) //video interface 0 + { + val = VIF0_CLK_GATE | (VIF0_CLK_GATE << 16); //gating vif0 + ret = rk616->write_dev(rk616,CRU_CLKSEL2_CON,&val); + + } + else //vide0 interface 1 + { + val = VIF1_CLK_GATE | (VIF1_CLK_GATE << 16); //gating vif1 + ret = rk616->write_dev(rk616,CRU_CLKSEL2_CON,&val); + + } + + dev_info(rk616->dev,"rk616 vif%d disable\n",id); + + return 0; +} + + +int rk616_vif_enable(struct mfd_rk616 *rk616,int id) +{ + u32 val = 0; + u32 offset = 0; + int ret; + + + if(id == 0) + { + val = (VIF0_CLK_BYPASS << 16) | (VIF0_CLK_GATE << 16); + offset = 0; + } + else + { + val = (VIF1_CLK_BYPASS << 16) |(VIF1_CLK_GATE << 16); + offset = 0x18; + } + + ret = rk616->write_dev(rk616,CRU_CLKSEL2_CON,&val); + + val = 0; + val |= (VIF0_DDR_CLK_EN <<16) | (VIF0_DDR_PHASEN_EN << 16) | (VIF0_DDR_MODE_EN << 16)| + (VIF0_EN <<16) | VIF0_EN; //disable ddr mode,enable VIF + ret = rk616->write_dev(rk616,VIF0_REG0 + offset,&val); + + + dev_info(rk616->dev,"rk616 vif%d enable\n",id); + + return 0; + +} +static int rk616_vif_bypass(struct mfd_rk616 *rk616,int id) +{ + u32 val = 0; + int ret; + + if(id == 0) + { + val = (VIF0_CLK_BYPASS | VIF0_CLK_BYPASS << 16); + } + else + { + val = (VIF1_CLK_BYPASS | VIF1_CLK_BYPASS << 16); + } + + ret = rk616->write_dev(rk616,CRU_CLKSEL2_CON,&val); + + dev_info(rk616->dev,"rk616 vif%d bypass\n",id); + return 0; +} + +static bool pll_sel_mclk12m(struct mfd_rk616 *rk616,int pll_id) +{ + if(pll_id == 0) //pll0 + { + if(rk616->route.pll0_clk_sel == PLL0_CLK_SEL(MCLK_12M)) + return true; + else + return false; + } + else + { + if(rk616->route.pll1_clk_sel == PLL1_CLK_SEL(MCLK_12M)) + return true; + else + return false; + } + + return false; +} + + + int rk616_vif_cfg(struct mfd_rk616 *rk616,rk_screen *screen,int id) { int ret = 0; @@ -20,35 +135,26 @@ int rk616_vif_cfg(struct mfd_rk616 *rk616,rk_screen *screen,int id) { if(!rk616->route.vif0_en) { - val = (VIF0_EN << 16); //disable vif0 - ret = rk616->write_dev(rk616,VIF0_REG0,&val); - clk_set_rate(rk616->mclk, 11289600); + rk616_vif_disable(rk616,id); return 0; } offset = 0; pll_id = rk616->route.vif0_clk_sel; - if(rk616->route.pll0_clk_sel == PLL0_CLK_SEL(MCLK_12M)) - pll_use_mclk12m = true; - else - pll_use_mclk12m = false; } else //vide0 interface 1 { if(!rk616->route.vif1_en) { - val = (VIF0_EN << 16); //disabl VIF1 - ret = rk616->write_dev(rk616,VIF1_REG0,&val); - clk_set_rate(rk616->mclk, 11289600); + rk616_vif_disable(rk616,id); return 0; } offset = 0x18; pll_id = (rk616->route.vif1_clk_sel >> 6); - if(rk616->route.pll1_clk_sel == PLL1_CLK_SEL(MCLK_12M)) - pll_use_mclk12m = true; - else - pll_use_mclk12m = false; + } + pll_use_mclk12m = pll_sel_mclk12m(rk616,pll_id); + if(pll_use_mclk12m) { clk_set_rate(rk616->mclk, 12000000); @@ -61,37 +167,42 @@ int rk616_vif_cfg(struct mfd_rk616 *rk616,rk_screen *screen,int id) return -EINVAL; } - - - val |= (VIF0_DDR_CLK_EN <<16) | (VIF0_DDR_PHASEN_EN << 16) | (VIF0_DDR_MODE_EN << 16)| - (VIF0_EN <<16) | VIF0_EN; //disable ddr mode,enable VIF - - ret = rk616->write_dev(rk616,VIF0_REG0 + offset,&val); + rk616_vif_disable(rk616,id); if( (screen->x_res == 1920) && (screen->y_res == 1080)) { if(pll_use_mclk12m) - rk616_pll_set_rate(rk616,pll_id,0xc11025,0x200000); + //rk616_pll_set_rate(rk616,pll_id,0xc11025,0x200000); + rk616_pll_set_rate(rk616,pll_id,0x028853de,0); else rk616_pll_set_rate(rk616,pll_id,0x02bf5276,0); + + val = (0xc1) | (0x01 <<16); } else if((screen->x_res == 1280) && (screen->y_res == 720)) { if(pll_use_mclk12m) - rk616_pll_set_rate(rk616,pll_id,0x01811025,0x200000); + //rk616_pll_set_rate(rk616,pll_id,0x01811025,0x200000); + rk616_pll_set_rate(rk616,pll_id,0x0288418c,0); else rk616_pll_set_rate(rk616,pll_id,0x1422014,0); + + val = (0xc1) | (0x01 <<16); + } else if((screen->x_res == 720)) { - if(pll_use_mclk12m) - rk616_pll_set_rate(rk616,pll_id,0x01413021,0xc00000); + if(pll_use_mclk12m ) + { + rk616_pll_set_rate(rk616,pll_id,0x0306510e,0); + } else rk616_pll_set_rate(rk616,pll_id,0x1c13015,0); + + val = (0x1) | (0x01 <<16); } - //val = fscreen->vif_hst | (fscreen->vif_vst<<16); - val = (0xc1) | (0x01 <<16); + ret = rk616->write_dev(rk616,VIF0_REG1 + offset,&val); val = (screen->hsync_len << 16) | (screen->hsync_len + screen->left_margin + @@ -112,41 +223,13 @@ int rk616_vif_cfg(struct mfd_rk616 *rk616,rk_screen *screen,int id) (screen->vsync_len + screen->upper_margin); ret = rk616->write_dev(rk616,VIF0_REG5 + offset,&val); - dev_info(rk616->dev,"rk616 vif%d enable\n",id); + rk616_vif_enable(rk616,id); return ret; } -static int rk616_vif_disable(struct mfd_rk616 *rk616,int id) -{ - u32 val = 0; - int ret = 0; - - printk(KERN_INFO "rk616 vif%d disable\n",id); - - if(id == 0) //video interface 0 - { - - val = (VIF0_EN << 16); //disable vif0 - ret = rk616->write_dev(rk616,VIF0_REG0,&val); - clk_set_rate(rk616->mclk, 11289600); - return 0; - - } - else //vide0 interface 1 - { - - val = (VIF0_EN << 16); //disabl VIF1 - ret = rk616->write_dev(rk616,VIF1_REG0,&val); - clk_set_rate(rk616->mclk, 11289600); - return 0; - } - - - return 0; -} static int rk616_scaler_disable(struct mfd_rk616 *rk616) { u32 val = 0; @@ -158,21 +241,18 @@ static int rk616_scaler_disable(struct mfd_rk616 *rk616) } int rk616_scaler_cfg(struct mfd_rk616 *rk616,rk_screen *screen) { - u32 val = 0; - int ret = 0; u32 scl_hor_mode,scl_ver_mode; u32 scl_v_factor,scl_h_factor; u32 scl_reg0_value,scl_reg1_value,scl_reg2_value; //scl_con,scl_h_factor,scl_v_factor, u32 scl_reg3_value,scl_reg4_value,scl_reg5_value,scl_reg6_value; //dsp_frame_hst,dsp_frame_vst,dsp_timing,dsp_act_timing u32 scl_reg7_value,scl_reg8_value; //dsp_hbor ,dsp_vbor u32 dst_frame_hst,dst_frame_vst; //ʱÐò»º´æ - u32 dst_htotal,dst_hs_end,dst_hact_st,dst_hact_end; //ÆÁÄ»typical h²ÎÊý - u32 dst_vtotal,dst_vs_end,dst_vact_st,dst_vact_end; //ÆÁÄ»typical v²ÎÊý + u32 dst_vact_st; u32 dsp_htotal,dsp_hs_end,dsp_hact_st,dsp_hact_end; //scalerÊä³öµÄtiming²ÎÊý u32 dsp_vtotal,dsp_vs_end,dsp_vact_st,dsp_vact_end; u32 dsp_hbor_end,dsp_hbor_st,dsp_vbor_end,dsp_vbor_st; - u32 src_w,src_h,src_htotal,src_vtotal,dst_w,dst_h,src_hact_st,src_vact_st; + u32 src_w,src_h,src_htotal,dst_w,dst_h,src_vact_st; u16 bor_right = 0; u16 bor_left = 0; u16 bor_up = 0; @@ -349,7 +429,7 @@ static int rk616_dual_input_cfg(struct mfd_rk616 *rk616,rk_screen *screen, route->vif0_en = 0; route->vif0_clk_sel = VIF0_CLKIN_SEL(VIF_CLKIN_SEL_PLL0); route->pll0_clk_sel = PLL0_CLK_SEL(LCD0_DCLK); - route->pll1_clk_sel = PLL1_CLK_SEL(MCLK_12M); + route->pll1_clk_sel = PLL1_CLK_SEL(LCD1_DCLK); route->vif1_clk_sel = VIF1_CLKIN_SEL(VIF_CLKIN_SEL_PLL1); route->hdmi_sel = HDMI_IN_SEL(HDMI_CLK_SEL_VIF1); if(enable) //hdmi plug in @@ -385,11 +465,7 @@ static int rk616_dual_input_cfg(struct mfd_rk616 *rk616,rk_screen *screen, { route->lvds_en = 0; } - else - { - dev_err(rk616->dev,"un supported interface:%d\n",screen->type); - return -EINVAL; - } + return 0; @@ -481,6 +557,9 @@ static int rk616_lcd0_input_lcd1_output_cfg(struct mfd_rk616 *rk616,rk_screen *s route->lcd1_input = 0; //lcd1 as out put route->lvds_en = 0; + //route->scl_en = 0; + //route->dither_sel = DITHER_IN_SEL(DITHER_SEL_VIF0); + return 0; } @@ -531,11 +610,7 @@ static int rk616_lcd0_unused_lcd1_input_cfg(struct mfd_rk616 *rk616,rk_screen *s { route->lvds_en = 0; } - else - { - dev_err(rk616->dev,"un supported interface:%d\n",screen->type); - return -EINVAL; - } + return 0; } @@ -606,7 +681,7 @@ static int rk616_router_cfg(struct mfd_rk616 *rk616) (VIF0_CLK_BYPASS << 16) |(route->sclin_sel) | (route->dither_sel) | (route->hdmi_sel) | (route->vif1_bypass) | (route->vif0_bypass) | (route->vif1_clk_sel)| (route->vif0_clk_sel); - ret = rk616->write_dev(rk616,CRU_CLKSE2_CON,&val); + ret = rk616->write_dev(rk616,CRU_CLKSEL2_CON,&val); return ret; } @@ -646,6 +721,7 @@ int rk616_set_vif(struct mfd_rk616 *rk616,rk_screen *screen,bool connect) { rk616_vif_disable(rk616,0); rk616_vif_disable(rk616,1); + clk_set_rate(rk616->mclk, 11289600); return 0; } #if defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF) diff --git a/drivers/video/display/transmitter/rk616_lvds.c b/drivers/video/display/transmitter/rk616_lvds.c index 04766b90b3e1..78d38eadbcd9 100644 --- a/drivers/video/display/transmitter/rk616_lvds.c +++ b/drivers/video/display/transmitter/rk616_lvds.c @@ -92,6 +92,7 @@ static int rk616_dither_cfg(struct mfd_rk616 *rk616,rk_screen *screen,bool enabl val = FRC_DCLK_INV | (FRC_DCLK_INV << 16); if((screen->face != OUT_P888) && enable) //enable frc dither if the screen is not 24bit val |= FRC_DITHER_EN | (FRC_DITHER_EN << 16); + //val |= (FRC_DITHER_EN << 16); else val |= (FRC_DITHER_EN << 16); ret = rk616->write_dev(rk616,FRC_REG,&val); diff --git a/drivers/video/rockchip/hdmi/rk_hdmi_lcdc.c b/drivers/video/rockchip/hdmi/rk_hdmi_lcdc.c index 22f38f356ea7..e20be70c7a7e 100755 --- a/drivers/video/rockchip/hdmi/rk_hdmi_lcdc.c +++ b/drivers/video/rockchip/hdmi/rk_hdmi_lcdc.c @@ -508,11 +508,12 @@ int hdmi_switch_fb(struct hdmi *hdmi, int vic) rc = hdmi_set_info(screen, hdmi->vic); - if(rc == 0) { - if(hdmi->set_vif) - hdmi->set_vif(screen,1); + if(rc == 0) { rk_fb_switch_screen(screen, 1, hdmi->lcdc->id); rk_fb_disp_scale(hdmi->xscale, hdmi->yscale, hdmi->lcdc->id); + if(hdmi->set_vif) + hdmi->set_vif(screen,1); + } kfree(screen); diff --git a/drivers/video/rockchip/hdmi/rk_hdmi_task.c b/drivers/video/rockchip/hdmi/rk_hdmi_task.c index 057e32d60554..9148464f20b0 100755 --- a/drivers/video/rockchip/hdmi/rk_hdmi_task.c +++ b/drivers/video/rockchip/hdmi/rk_hdmi_task.c @@ -234,6 +234,7 @@ void hdmi_work(struct work_struct *work) } break; case SYSTEM_CONFIG: + hdmi->remove(); if(hdmi->autoconfig) hdmi->vic = hdmi_find_best_mode(hdmi, 0); else diff --git a/include/linux/mfd/rk616.h b/include/linux/mfd/rk616.h index c9a87995e201..e97057b7ce2d 100644 --- a/include/linux/mfd/rk616.h +++ b/include/linux/mfd/rk616.h @@ -5,6 +5,7 @@ #include #include #include +#include #define VIF0_REG0 0x0000 #define VIF0_DDR_CLK_EN (1<<3) @@ -77,7 +78,7 @@ #define CRU_CODEC_DIV 0x0060 -#define CRU_CLKSE2_CON 0x0064 +#define CRU_CLKSEL2_CON 0x0064 #define SCL_IN_SEL_MASK (1<<31) #define DITHER_IN_SEL_MASK (1<<30) #define HDMI_IN_SEL_MASK (3<<28) @@ -222,6 +223,7 @@ enum lvds_mode { }; struct rk616_platform_data { int (*power_init)(void); + int (*power_deinit)(void); int scl_rate; enum lcd_port_func lcd0_func; enum lcd_port_func lcd1_func; @@ -261,6 +263,8 @@ struct mfd_rk616 { struct rk616_route route; //display path router struct i2c_client *client; struct clk *mclk; + u64 pll0_rate; + u64 pll1_rate; struct dentry *debugfs_dir; int (*read_dev)(struct mfd_rk616 *rk616,u16 reg,u32 *pval); int (*write_dev)(struct mfd_rk616 *rk616,u16 reg,u32 *pval); -- 2.34.1