mfd:rk616:vif:support dual display and scaler
authoryxj <yxj@rock-chips.com>
Sun, 28 Apr 2013 03:26:11 +0000 (11:26 +0800)
committeryxj <yxj@rock-chips.com>
Sun, 28 Apr 2013 04:20:39 +0000 (12:20 +0800)
drivers/mfd/rk616-core.c
drivers/video/display/transmitter/Kconfig
drivers/video/display/transmitter/Makefile
drivers/video/display/transmitter/rk616_lvds.c [deleted file]
drivers/video/display/transmitter/rk616_vif.c [new file with mode: 0644]
include/linux/mfd/rk616.h

index 864dc23511a1f04597ba4f4ecdd90560b9ef7f65..e88f1379366761697890f7c51fa74a8a2967697e 100644 (file)
@@ -21,7 +21,7 @@
 
 static struct mfd_cell rk616_devs[] = {
        {
-               .name = "rk616-lvds",
+               .name = "rk616-vif",
                .id = 0,
        },
        {
@@ -113,7 +113,7 @@ static int rk616_reg_show(struct seq_file *s, void *v)
        {
                rk616->read_dev(rk616,i,&val);
                if(i%16==0)
-                       seq_printf(s,"\n%04x:",i);
+                       seq_printf(s,"\n0x%04x:",i);
                seq_printf(s," %08x",val);
        }
        seq_printf(s,"\n");
@@ -246,7 +246,7 @@ static  int  rk616_pll_wait_lock(struct mfd_rk616 *rk616,int id)
                ret = rk616->read_dev(rk616,CRU_PLL0_CON1 + offset,&val);
                if (val&PLL0_LOCK)
                {
-                       dev_info(rk616->dev,"pll locked\n");
+                       dev_info(rk616->dev,"PLL%d locked\n",id);
                        break;
                }
                msleep(1);
@@ -261,28 +261,19 @@ static  int  rk616_pll_wait_lock(struct mfd_rk616 *rk616,int id)
 }
 
 
-int rk616_pll_set_rate(struct mfd_rk616 *rk616,int id,u32 fin,u32 fout)
+int rk616_pll_set_rate(struct mfd_rk616 *rk616,int id,u32 cfg_val,u32 frac)
 {
        u32 val = 0;
        int ret;
        int offset;
-       u32 refdiv,fbdiv,postdiv1,postdiv2,frac;
-       int mode; //pll div mode,integer or frac
-
-
-       ret = rk616_pll_par_calc(fin,fout,&refdiv,&fbdiv,
-                                       &postdiv1,&postdiv2,&frac);
-       refdiv = 4;
-       fbdiv = 32;
-       postdiv1 = 2;
-       postdiv2 = 4;
-       frac = 0;
-       if(ret < 0)
-       {
-               return -EINVAL;
-       }
-
-       mode = !frac;
+       u16 con0 = cfg_val & 0xffff;
+       u16 con1 = (cfg_val >> 16)&0xffff;
+       u32 fbdiv = con0 & 0xfff;
+       u32 postdiv1 = (con0 >> 12)&0x7;
+       u32 refdiv = con1 & 0x3f;
+       u32 postdiv2 = (con1 >> 6) & 0x7;
+       u8 mode = !frac;
+       
        
        if(id == 0)  //PLL0
        {
@@ -294,8 +285,6 @@ int rk616_pll_set_rate(struct mfd_rk616 *rk616,int id,u32 fin,u32 fout)
        }
 
 
-       
-       
        val = PLL0_PWR_DN | (PLL0_PWR_DN << 16);
        ret = rk616->write_dev(rk616,CRU_PLL0_CON1 + offset,&val);
 
@@ -306,6 +295,9 @@ int rk616_pll_set_rate(struct mfd_rk616 *rk616,int id,u32 fin,u32 fout)
        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);
@@ -326,23 +318,20 @@ static int rk616_clk_common_init(struct mfd_rk616 *rk616)
        u32 val = 0;
        int ret;
 
-       val = PLL1_CLK_SEL(1) | PLL0_CLK_SEL(0) | LCD1_CLK_DIV(0) | LCD0_CLK_DIV(0) |
-               PLL1_CLK_SEL_MASK | PLL0_CLK_SEL_MASK | LCD1_CLK_DIV_MASK | 
-               LCD0_CLK_DIV_MASK; //pll1 clk from lcdc1_dclk,pll0 clk from lcdc0_dclk,mux_lcdx = lcdx_clk
+       val = PLL1_CLK_SEL(LCD1_DCLK) | PLL0_CLK_SEL(LCD0_DCLK) | LCD1_CLK_DIV(0) | 
+               LCD0_CLK_DIV(0) | PLL1_CLK_SEL_MASK | PLL0_CLK_SEL_MASK | 
+               LCD1_CLK_DIV_MASK | LCD0_CLK_DIV_MASK; //pll1 clk from lcdc1_dclk,pll0 clk from lcdc0_dclk,mux_lcdx = lcdx_clk
        ret = rk616->write_dev(rk616,CRU_CLKSEL0_CON,&val);
 
-       val = CODEC_MCLK_SEL(2) | CODEC_MCLK_SEL_MASK; //codec mclk from clkin
+       val = SCLK_SEL(SCLK_SEL_PLL1) | CODEC_MCLK_SEL(CODEC_MCLK_SEL_12M) |
+               CODEC_MCLK_SEL_MASK | SCLK_SEL_MASK; //codec mclk from clkin
        ret = rk616->write_dev(rk616,CRU_CLKSEL1_CON,&val);
        
        val = 0; //codec mck = clkin
        ret = rk616->write_dev(rk616,CRU_CODEC_DIV,&val);
 
-#if 1
        val = (PLL0_BYPASS) | (PLL0_BYPASS << 16);  //bypass pll0 
        ret = rk616->write_dev(rk616,CRU_PLL0_CON0,&val);
-#else
-       rk616_pll_set_rate(rk616,0,66500000,66500000);
-#endif
 
        val = (PLL1_BYPASS) | (PLL1_BYPASS << 16);
        ret = rk616->write_dev(rk616,CRU_PLL1_CON0,&val);
@@ -403,6 +392,7 @@ static int rk616_i2c_probe(struct i2c_client *client,const struct i2c_device_id
        }
        rk616->read_dev = rk616_i2c_read_reg;
        rk616->write_dev = rk616_i2c_write_reg;
+       
 #if defined(CONFIG_DEBUG_FS)
        rk616->debugfs_dir = debugfs_create_dir("rk616", NULL);
        if (IS_ERR(rk616->debugfs_dir))
@@ -410,7 +400,7 @@ static int rk616_i2c_probe(struct i2c_client *client,const struct i2c_device_id
                dev_err(rk616->dev,"failed to create debugfs dir for rk616!\n");
        }
        else
-               debugfs_create_file("rk616-core", S_IRUSR,rk616->debugfs_dir,rk616,&rk616_reg_fops);
+               debugfs_create_file("core", S_IRUSR,rk616->debugfs_dir,rk616,&rk616_reg_fops);
 #endif
        rk616_clk_common_init(rk616);
        ret = mfd_add_devices(rk616->dev, -1,
index 0d16b082b9278be21b36b501468e21810c83f47a..a5d6248c1ebe74148d713faf314671684239b831 100644 (file)
@@ -11,8 +11,8 @@ config RK610_LVDS
        help
                Support Jetta(RK610) to output LCD1 and LVDS.
 
-config RK616_LVDS
-        bool "RK616(Jetta B) lvds,lcd,scaler transmitter support"
+config RK616_VIF
+        bool "RK616(JettaB) lvds,lcd,scaler vido interface support"
         depends on MFD_RK616
         help
            RK616(Jetta B) LVDS,LCD,scaler transmitter support.
index 7c9ccf2a360c7bc2800da945154c6fb4d25fa930..b74e537c44ffdc8857cd2ad7e8525a20887aeca8 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for display transmitter like lvds edp mipi
 #
 obj-$(CONFIG_RK610_LVDS)         += rk610_lcd.o
-obj-$(CONFIG_RK616_LVDS)          += rk616_lvds.o
+obj-$(CONFIG_RK616_VIF)          += rk616_vif.o
 obj-$(CONFIG_TC358768_RGB2MIPI)   += mipi_dsi.o tc358768.o
 obj-$(CONFIG_SSD2828_RGB2MIPI)   += mipi_dsi.o ssd2828.o
 obj-$(CONFIG_DP_ANX6345)          += dp_anx6345.o
diff --git a/drivers/video/display/transmitter/rk616_lvds.c b/drivers/video/display/transmitter/rk616_lvds.c
deleted file mode 100644 (file)
index 6debbce..0000000
+++ /dev/null
@@ -1,532 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/mfd/rk616.h>
-#include <linux/rk_fb.h>
-
-struct mfd_rk616 *g_rk616;
-
-/*rk616 video interface config*/
-static int rk616_vif_cfg(struct mfd_rk616 *rk616,rk_screen *screen,int id)
-{
-       int ret = 0;
-       u32 val = 0;
-       int offset = 0;
-       if(id == 0) //video interface 0
-       {
-               if(!rk616->route.vif0_en)
-               {
-                       val = (VIF0_EN << 16); //disable vif0
-                       ret = rk616->write_dev(rk616,VIF0_REG0,&val);
-                       return 0;
-               }
-               offset = 0;
-       }
-       else       //vide0 interface 1
-       {
-               if(!rk616->route.vif1_en)
-               {
-                       val = (VIF0_EN << 16); //disabl VIF1
-                       ret = rk616->write_dev(rk616,VIF1_REG0,&val);
-                       return 0;
-               }
-               offset = 0x18;
-       }
-       
-       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);  
-
-       val = (1) | (1<<16);
-       ret = rk616->write_dev(rk616,VIF0_REG1 + offset,&val);
-
-       val = (screen->hsync_len << 16) | (screen->hsync_len + screen->left_margin + 
-               screen->right_margin + screen->x_res);
-       ret = rk616->write_dev(rk616,VIF0_REG2 + offset,&val);
-
-       
-       val = ((screen->hsync_len + screen->left_margin + screen->x_res)<<16) |
-               (screen->hsync_len + screen->left_margin);
-       ret = rk616->write_dev(rk616,VIF0_REG3 + offset,&val);
-
-       val = (screen->vsync_len << 16) | (screen->vsync_len + screen->upper_margin + 
-               screen->lower_margin + screen->y_res);
-       ret = rk616->write_dev(rk616,VIF0_REG4 + offset,&val);
-
-
-       val = ((screen->vsync_len + screen->upper_margin + screen->y_res)<<16) |
-               (screen->vsync_len + screen->upper_margin);
-       ret = rk616->write_dev(rk616,VIF0_REG5 + offset,&val);
-       
-       return ret;
-       
-}
-
-
-
-static 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 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 pll_value,T_frm_st;
-       u16 bor_right = 0;
-       u16 bor_left = 0;
-       u16 bor_up = 0;
-       u16 bor_down = 0;
-       u8 hor_down_mode = 1;  //default use Proprietary averaging filter
-       u8 ver_down_mode = 1;
-       u8 bic_coe_sel = 2;
-       rk_screen *src;
-       rk_screen *dst;
-       u32 DCLK_IN;
-
-       double fk = 1.0;
-       struct rk616_route *route = &rk616->route;
-
-
-       if(!route->scl_en)
-       {
-               val &= (~SCL_EN);       //disable scaler
-               val |= (SCL_EN<<16);
-               ret = rk616->write_dev(rk616,SCL_REG0,&val);
-               return 0;
-       }
-       
-
-       src = screen;
-       dst = screen;
-       DCLK_IN = src->pixclock;
-
-
-#if 1
-
-       src_htotal = src->hsync_len + src->left_margin + src->x_res + src->right_margin;
-       src_vact_st = src->vsync_len + src->upper_margin  ;
-       dst_vact_st = dst->vsync_len + dst->upper_margin;
-
-       dsp_htotal    = dst->hsync_len + dst->left_margin + dst->x_res + dst->right_margin; //dst_htotal ;
-       dsp_hs_end    = dst->hsync_len;
-
-       dsp_vtotal    = dst->vsync_len + dst->upper_margin + dst->y_res + dst->lower_margin;
-       dsp_vs_end    = dst->vsync_len;
-
-       dsp_hbor_end  = dst->hsync_len + dst->left_margin + dst->x_res;
-       dsp_hbor_st   = dst->hsync_len + dst->left_margin  ;
-       dsp_vbor_end  = dst->vsync_len + dst->upper_margin + dst->y_res; //dst_vact_end ;
-       dsp_vbor_st   = dst_vact_st  ;
-
-       dsp_hact_st   = dsp_hbor_st  + bor_left;
-       dsp_hact_end  = dsp_hbor_end - bor_right; 
-       dsp_vact_st   = dsp_vbor_st  + bor_up;
-       dsp_vact_end  = dsp_vbor_end - bor_down; 
-
-       src_w = src->x_res;
-       src_h = src->y_res;
-       dst_w = dsp_hact_end - dsp_hact_st ;
-       dst_h = dsp_vact_end - dsp_vact_st ;
-
-
-       pll_value = (DCLK_IN*dsp_htotal*(dsp_vact_end-dsp_vact_st))/(src_htotal*src_h);
-       dev_info(rk616->dev,"SCALER CLK Frq  =%u\n",pll_value);
-
-       T_frm_st = ((src_vact_st + 7)*src_htotal/DCLK_IN) -(dst_vact_st*dst_htotal)/pll_value;
-       if(T_frm_st <0)
-       {
-               T_frm_st = (src_htotal * src_vtotal)/DCLK_IN + T_frm_st;
-       }
-        
-       dst_frame_vst = (T_frm_st * DCLK_IN) / src_htotal ;
-       dst_frame_hst = (u32)(T_frm_st * DCLK_IN) % src_htotal ;    //dst
-
-       dev_info(rk616->dev,"scaler:dst_frame_h_st =%d\n"
-               "dst_frame_v_st =%d\n",
-               dst_frame_hst,dst_frame_vst);
-
-
-       if(src_w > dst_w)         //ÅжÏhorµÄËõ·Åģʽ 0£ºno_scl 1£ºscl_up 2£ºscl_down
-       {
-               scl_hor_mode = 0x2;   //scl_down
-               if(hor_down_mode == 0)//bilinear
-               {
-                       if((src_w-1)/(dst_w-1) > 2)
-                       {
-                               scl_h_factor = ((src_w-1)<<14)/(dst_w-1);
-                       }
-                       else
-                               scl_h_factor = ((src_w-2)<<14)/(dst_w-1);
-               }
-               else  //average
-               {
-                       scl_h_factor = ((dst_w)<<16)/(src_w-1);
-               }
-       }
-       else if(src_w == dst_w)
-       {
-               scl_hor_mode = 0x0;   //no_Scl
-               scl_h_factor = 0x0;
-       } 
-       else 
-       {
-               scl_hor_mode = 0x1;   //scl_up
-               scl_h_factor = ((src_w-1)<<16)/(dst_w-1);
-       } 
-    
-       if(src_h > dst_h)         //ÅжÏverµÄËõ·Åģʽ 0£ºno_scl 1£ºscl_up 2£ºscl_down
-       {
-               scl_ver_mode = 0x2;   //scl_down
-               if(ver_down_mode == 0)//bilinearhor_down_mode,u8 ver_down_mode
-               {
-                       if((src_h-1)/(dst_h-1) > 2)
-                       {
-                               scl_v_factor = ((src_h-1)<<14)/(dst_h-1);
-                       }
-                       else
-                               scl_v_factor = ((src_h-2)<<14)/(dst_h-1);
-               }
-               else
-               {
-                       scl_v_factor = ((dst_h)<<16)/(src_h-1);
-               }
-       }
-       else if(src_h == dst_h)
-       {
-               scl_ver_mode = 0x0;   //no_Scl
-               scl_v_factor = 0x0;
-       }
-       else 
-       {
-               scl_ver_mode = 0x1;   //scl_up
-               scl_v_factor = ((src_h-1)<<16)/(dst_h-1);
-       }
-
-       //control   register0 
-       scl_reg0_value = (0x1ff<<16) | SCL_EN | (scl_hor_mode<<1) |
-                       (scl_ver_mode<<3) | (bic_coe_sel<<5) | 
-                       (hor_down_mode<<7) | (ver_down_mode<<8) ;
-       //factor    register1 
-       scl_reg1_value = (scl_v_factor << 16) | scl_h_factor ;
-       //dsp_frame register2 
-       scl_reg2_value = dst_frame_vst<<16 | dst_frame_hst ;
-       //dsp_h     register3
-       scl_reg3_value = dsp_hs_end<<16 | dsp_htotal ;
-       //dsp_hact  register4
-       scl_reg4_value = dsp_hact_end <<16 | dsp_hact_st ;
-       //dsp_v     register5
-       scl_reg5_value = dsp_vs_end<<16 | dsp_vtotal ;
-       //dsp_vact  register6
-       scl_reg6_value = dsp_vact_end<<16 | dsp_vact_st ;
-       //hbor      register7
-       scl_reg7_value = dsp_hbor_end<<16 | dsp_hbor_st ;
-       //vbor      register8
-       scl_reg8_value = dsp_vbor_end<<16 | dsp_vbor_st ;
-
-    
-       rk616->write_dev(rk616,SCL_REG0,&scl_reg0_value);  
-       rk616->write_dev(rk616,SCL_REG1,&scl_reg1_value);  
-       rk616->write_dev(rk616,SCL_REG2,&scl_reg2_value);  
-       rk616->write_dev(rk616,SCL_REG3,&scl_reg3_value);  
-       rk616->write_dev(rk616,SCL_REG4,&scl_reg4_value);  
-       rk616->write_dev(rk616,SCL_REG5,&scl_reg5_value);  
-       rk616->write_dev(rk616,SCL_REG6,&scl_reg6_value);  
-       rk616->write_dev(rk616,SCL_REG7,&scl_reg7_value);  
-       rk616->write_dev(rk616,SCL_REG8,&scl_reg8_value);  
-#endif
-       return 0;
-       
-}
-static int  rk616_set_router(struct mfd_rk616 *rk616,rk_screen *screen)
-{
-       struct rk616_platform_data *pdata = rk616->pdata;
-       struct rk616_route *route = &rk616->route;
-       if((pdata->lcd0_func == INPUT) && (pdata->lcd1_func == INPUT))
-       {
-               route->vif0_bypass = 1;
-               route->vif0_en     = 0;
-               route->vif1_bypass = 1;
-               route->vif1_en     = 0;
-               route->sclin_sel   = 0; //0:vif0 1:vif1
-               route->scl_en      = 0;
-               route->dither_sel  = 0; //dither from vif0
-               route->hdmi_sel    = 0;
-               route->lcd1_input  = 1; 
-               route->lvds_en     = 1;
-               if(screen->type == SCREEN_RGB)
-               {
-                       route->lvds_mode   = 0; //rgb output 
-               }
-               else if(screen->type == SCREEN_LVDS)
-               {
-                       route->lvds_mode = 1;
-                       route->lvds_ch_nr = pdata->lvds_ch_nr;
-               }
-               #if 0
-               else
-               {
-                       dev_err(rk616->dev,"un supported interface:%d\n",screen->type);
-                       return -EINVAL;
-               }
-               #endif
-                       
-               dev_info(rk616->dev,"rk616 use dual input for dual display!\n");
-       }
-       else if((pdata->lcd0_func == INPUT) && (pdata->lcd1_func == UNUSED))
-       {
-               route->vif0_bypass = 1;
-               route->vif0_en     = 0;
-               route->vif1_bypass = 1;
-               route->vif1_en     = 0;
-               route->sclin_sel   = 0; //from vif0
-               route->scl_en      = 1;
-               route->dither_sel  = 1; //dither from sclaer
-               route->hdmi_sel    = 2;//from vif0
-               route->lcd1_input  = 0;  
-               route->lvds_en     = 1;
-               if(screen->type == SCREEN_RGB)
-               {
-                       route->lvds_mode   = 0; //rgb output 
-               }
-               else if(screen->type == SCREEN_LVDS)
-               {
-                       route->lvds_mode = 1;
-                       route->lvds_ch_nr = pdata->lvds_ch_nr;
-               }
-               else
-               {
-                       dev_err(rk616->dev,"un supported interface:%d\n",screen->type);
-                       return -EINVAL;
-               }
-                       
-               dev_info(rk616->dev,
-                       "rk616 use lcd0 as input and lvds/rgb "
-                       "port as output for dual display\n");
-       }
-       else if((pdata->lcd0_func == INPUT) && (pdata->lcd1_func == OUTPUT))
-       {
-               route->vif0_bypass = 1;
-               route->vif0_en = 0;
-               route->vif1_bypass = 1;
-               route->vif1_en = 0;
-               route->sclin_sel = 0;  // scl from vif0
-               route->scl_en   = 1;
-               route->dither_sel = 0;
-               route->hdmi_sel = 2;  //hdmi from lcd0
-               route->lcd1_input = 0; //lcd1 as out put
-               route->lvds_en  = 0;
-               dev_info(rk616->dev,
-                       "rk616 use lcd0 as input and lcd1 as"
-                       "output for dual display\n");
-
-       }
-       else if((pdata->lcd0_func == UNUSED) && (pdata->lcd1_func == INPUT))
-       {
-               route->vif0_bypass = 1;
-               route->vif0_en     = 0;
-               route->vif1_bypass = 1;
-               route->vif1_en     = 0;
-               route->sclin_sel   = 1; //from vif1
-               route->scl_en      = 1;
-               route->dither_sel  = 1; //dither from sclaer
-               route->hdmi_sel    = 0; //from vif1
-               route->lcd1_input  = 1;  
-               route->lvds_en     = 1;
-               if(screen->type == SCREEN_RGB)
-               {
-                       route->lvds_mode   = 0; //rgb output 
-               }
-               else if(screen->type == SCREEN_LVDS)
-               {
-                       route->lvds_mode = 1;
-                       route->lvds_ch_nr = pdata->lvds_ch_nr;
-               }
-               else
-               {
-                       dev_err(rk616->dev,"un supported interface:%d\n",screen->type);
-                       return -EINVAL;
-               }
-                       
-               
-       }
-       else
-       {
-               dev_err(rk616->dev,
-                       "invalid configration,please check your"
-                       "rk616_platform_data setting in your board file!\n");   
-       }
-
-       return 0;
-       
-}
-static int rk616_display_router_cfg(struct mfd_rk616 *rk616,rk_screen *screen)
-{
-       u32 val = 0;
-       int ret;
-       struct rk616_route *route = &rk616->route;
-
-       
-
-       ret = rk616_set_router(rk616,screen);
-       if(ret < 0)
-               return ret;
-       
-       val = (SCLIN_CLK_SEL << 16) | (DITHER_CLK_SEL << 16) | (HDMI_CLK_SEL_MASK) | 
-               (VIF1_CLK_BYPASS << 16) | (VIF0_CLK_BYPASS << 16) |(route->sclin_sel<<15) | 
-               (route->dither_sel<<14) | (route->hdmi_sel<<12) | (route->vif1_bypass<<7) | 
-               (route->vif0_bypass<<1); 
-       ret = rk616->write_dev(rk616,CRU_CLKSE2_CON,&val);
-
-       if(!route->lvds_en)  //lvds port is not used ,power down lvds
-       {
-               val &= ~(LVDS_CH1TTL_EN | LVDS_CH0TTL_EN | LVDS_CH1_PWR_EN |
-                       LVDS_CH0_PWR_EN | LVDS_CBG_PWR_EN);
-               val |= LVDS_PLL_PWR_DN | (LVDS_CH1TTL_EN << 16) | (LVDS_CH0TTL_EN << 16) |
-                       (LVDS_CH1_PWR_EN << 16) | (LVDS_CH0_PWR_EN << 16) |
-                       (LVDS_CBG_PWR_EN << 16) | (LVDS_PLL_PWR_DN << 16);
-               ret = rk616->write_dev(rk616,CRU_LVDS_CON0,&val);
-
-               if(!route->lcd1_input)  //set lcd1 port for output as RGB interface
-               {
-                       val = (LCD1_INPUT_EN << 16);
-                       ret = rk616->write_dev(rk616,CRU_IO_CON0,&val);
-               }
-       }
-       else
-       {
-               if(route->lvds_mode)  //lvds mode
-               {
-
-                       if(route->lvds_ch_nr == 2) //dual lvds channel
-                       {
-                               val &= ~(LVDS_CH0TTL_EN | LVDS_CH1TTL_EN);
-                               val = (LVDS_DCLK_INV)  | (LVDS_CH1_PWR_EN) |(LVDS_CH0_PWR_EN) | 
-                                       (LVDS_CBG_PWR_EN) | (LVDS_CH_SEL) | (LVDS_OUT_FORMAT(screen->hw_format)) | 
-                                       (LVDS_CH0TTL_EN << 16) | (LVDS_CH1TTL_EN << 16) |(LVDS_CH1_PWR_EN << 16) | 
-                                       (LVDS_CH0_PWR_EN << 16) | (LVDS_CBG_PWR_EN << 16) | (LVDS_CH_SEL << 16) | 
-                                       (LVDS_OUT_FORMAT_MASK);
-                               ret = rk616->write_dev(rk616,CRU_LVDS_CON0,&val);
-                               
-                               dev_info(rk616->dev,"rk616 use dual lvds channel.......\n");
-                       }
-                       else //single lvds channel
-                       {
-                               val = 0;
-                               val &= ~(LVDS_CH0TTL_EN | LVDS_CH1TTL_EN | LVDS_CH1_PWR_EN | LVDS_PLL_PWR_DN | LVDS_CH_SEL); //use channel 0
-                               val |= (LVDS_CH0_PWR_EN) |(LVDS_CBG_PWR_EN) | (LVDS_OUT_FORMAT(screen->hw_format)) | 
-                                     (LVDS_CH0TTL_EN << 16) | (LVDS_CH1TTL_EN << 16) |(LVDS_CH0_PWR_EN << 16) | 
-                                      (LVDS_DCLK_INV ) | (LVDS_CH0TTL_EN << 16) | (LVDS_CH1TTL_EN << 16) |(LVDS_CH0_PWR_EN << 16) | 
-                                       (LVDS_CBG_PWR_EN << 16)|(LVDS_CH_SEL << 16) | (LVDS_PLL_PWR_DN << 16)| 
-                                      (LVDS_OUT_FORMAT_MASK) | (LVDS_DCLK_INV << 16);
-                               ret = rk616->write_dev(rk616,CRU_LVDS_CON0,&val);
-
-                               dev_info(rk616->dev,"rk616 use single lvds channel.......\n");
-                               
-                       }
-
-               }
-               else //mux lvds port to RGB mode
-               {
-                       val &= ~(LVDS_CBG_PWR_EN| LVDS_CH1_PWR_EN | LVDS_CH0_PWR_EN);
-                       val |= (LVDS_CH0TTL_EN)|(LVDS_CH1TTL_EN )|(LVDS_PLL_PWR_DN)|
-                               (LVDS_CH0TTL_EN<< 16)|(LVDS_CH1TTL_EN<< 16)|(LVDS_CH1_PWR_EN << 16) | 
-                               (LVDS_CH0_PWR_EN << 16)|(LVDS_CBG_PWR_EN << 16)|(LVDS_PLL_PWR_DN << 16);
-                       ret = rk616->write_dev(rk616,CRU_LVDS_CON0,&val);
-
-                       val &= ~(LVDS_OUT_EN);
-                       val |= (LVDS_OUT_EN << 16);
-                       ret = rk616->write_dev(rk616,CRU_IO_CON0,&val);
-                       dev_info(rk616->dev,"rk616 use RGB output.....\n");
-                       
-               }
-       }
-       
-       
-       val = FRC_DCLK_INV | (FRC_DCLK_INV << 16);
-       ret = rk616->write_dev(rk616,FRC_REG,&val);
-       
-       ret = rk616_vif_cfg(rk616,screen,0);
-       ret = rk616_vif_cfg(rk616,screen,1);
-       ret = rk616_scaler_cfg(rk616,screen);
-
-       return 0;
-       
-}
-int rk610_lcd_scaler_set_param(rk_screen *screen,bool enable )//enable:0 bypass 1: scale
-{
-       int ret;
-       struct mfd_rk616 *rk616 = g_rk616;
-       if(!rk616)
-       {
-               printk(KERN_ERR "%s:mfd rk616 is null!\n",__func__);
-               return -1;
-       }
-       rk616_display_router_cfg(rk616,screen);
-       return ret;
-}
-
-static int rk616_lvds_probe(struct platform_device *pdev)
-{
-
-       struct mfd_rk616 *rk616 = dev_get_drvdata(pdev->dev.parent);
-       if(!rk616)
-       {
-               dev_err(&pdev->dev,"null mfd device rk616!\n");
-               return -ENODEV;
-       }
-       else
-               g_rk616 = rk616;
-       
-
-       dev_info(&pdev->dev,"rk616 lvds probe success!\n");
-
-       return 0;
-       
-}
-
-static int rk616_lvds_remove(struct platform_device *pdev)
-{
-       
-       return 0;
-}
-
-static void rk616_lvds_shutdown(struct platform_device *pdev)
-{
-       
-       return;
-}
-
-static struct platform_driver rk616_lvds_driver = {
-       .driver         = {
-               .name   = "rk616-lvds",
-               .owner  = THIS_MODULE,
-       },
-       .probe          = rk616_lvds_probe,
-       .remove         = rk616_lvds_remove,
-       .shutdown       = rk616_lvds_shutdown,
-};
-
-static int __init rk616_lvds_init(void)
-{
-       return platform_driver_register(&rk616_lvds_driver);
-}
-subsys_initcall_sync(rk616_lvds_init);
-
-static void __exit rk616_lvds_exit(void)
-{
-       platform_driver_unregister(&rk616_lvds_driver);
-}
-module_exit(rk616_lvds_exit);
-
diff --git a/drivers/video/display/transmitter/rk616_vif.c b/drivers/video/display/transmitter/rk616_vif.c
new file mode 100644 (file)
index 0000000..b2ed195
--- /dev/null
@@ -0,0 +1,688 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mfd/rk616.h>
+#include <linux/rk_fb.h>
+
+struct mfd_rk616 *g_rk616;
+extern int rk616_pll_set_rate(struct mfd_rk616 *rk616,int id,u32 cfg_val,u32 frac);
+
+/*rk616 video interface config*/
+static int rk616_vif_cfg(struct mfd_rk616 *rk616,rk_screen *fscreen,int id)
+{
+       int ret = 0;
+       u32 val = 0;
+       int offset = 0;
+       int pll_id;
+       rk_screen *screen  = NULL;
+       
+       if(id == 0) //video interface 0
+       {
+               if(!rk616->route.vif0_en)
+               {
+                       val = (VIF0_EN << 16); //disable vif0
+                       ret = rk616->write_dev(rk616,VIF0_REG0,&val);
+                       return 0;
+               }
+               offset = 0;
+               pll_id = rk616->route.vif0_clk_sel; 
+       }
+       else       //vide0 interface 1
+       {
+               if(!rk616->route.vif1_en)
+               {
+                       val = (VIF0_EN << 16); //disabl VIF1
+                       ret = rk616->write_dev(rk616,VIF1_REG0,&val);
+                       return 0;
+               }
+               offset = 0x18;
+               pll_id = (rk616->route.vif1_clk_sel >> 6);
+       }
+
+       screen = fscreen->ext_screen;
+       if(!screen)
+       {
+               dev_err(rk616->dev,"%s:screen is null.........\n",__func__);
+               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);  
+
+       if( (screen->x_res == 1920) && (screen->y_res == 1080))
+       {
+               rk616_pll_set_rate(rk616,pll_id,0x02bf5276,0);
+       }
+       else if((screen->x_res == 1280) && (screen->y_res == 720))
+       {
+               rk616_pll_set_rate(rk616,pll_id,0x1422014,0);
+       }
+       else if((screen->x_res == 720))
+       {
+               rk616_pll_set_rate(rk616,pll_id,0x1c13015,0);
+       }
+
+       val = fscreen->vif_hst | (fscreen->vif_vst<<16);
+       ret = rk616->write_dev(rk616,VIF0_REG1 + offset,&val);
+
+       val = (screen->hsync_len << 16) | (screen->hsync_len + screen->left_margin + 
+               screen->right_margin + screen->x_res);
+       ret = rk616->write_dev(rk616,VIF0_REG2 + offset,&val);
+
+       
+       val = ((screen->hsync_len + screen->left_margin + screen->x_res)<<16) |
+               (screen->hsync_len + screen->left_margin);
+       ret = rk616->write_dev(rk616,VIF0_REG3 + offset,&val);
+
+       val = (screen->vsync_len << 16) | (screen->vsync_len + screen->upper_margin + 
+               screen->lower_margin + screen->y_res);
+       ret = rk616->write_dev(rk616,VIF0_REG4 + offset,&val);
+
+
+       val = ((screen->vsync_len + screen->upper_margin + screen->y_res)<<16) |
+               (screen->vsync_len + screen->upper_margin);
+       ret = rk616->write_dev(rk616,VIF0_REG5 + offset,&val);
+       
+       return ret;
+       
+}
+
+
+
+static 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 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;
+       u16 bor_right = 0;
+       u16 bor_left = 0;
+       u16 bor_up = 0;
+       u16 bor_down = 0;
+       u8 hor_down_mode = 0;  //1:average,0:bilinear
+       u8 ver_down_mode = 0;
+       u8 bic_coe_sel = 2;
+       rk_screen *src;
+       rk_screen *dst;
+       int pll_id;
+
+       struct rk616_route *route = &rk616->route;
+
+
+       if(!route->scl_en)
+       {
+               val &= (~SCL_EN);       //disable scaler
+               val |= (SCL_EN<<16);
+               ret = rk616->write_dev(rk616,SCL_REG0,&val);
+               return 0;
+       }
+       
+       
+       dst = screen;
+       if(!dst)
+       {
+               dev_err(rk616->dev,"%s:screen is null!\n",__func__);
+               return -EINVAL;
+       }
+
+       if(route->scl_bypass)
+               src = dst;
+       else
+               src = screen->ext_screen;
+       
+       if(route->sclk_sel == SCLK_SEL(SCLK_SEL_PLL0))
+               pll_id = 0;
+       else
+               pll_id = 1;
+       rk616_pll_set_rate(rk616,pll_id,dst->pll_cfg_val,dst->frac);
+       dst_frame_vst = dst->scl_vst;
+       dst_frame_hst = dst->scl_hst;
+
+
+#if 1
+
+       src_htotal = src->hsync_len + src->left_margin + src->x_res + src->right_margin;
+       src_vact_st = src->vsync_len + src->upper_margin  ;
+       dst_vact_st = dst->vsync_len + dst->upper_margin;
+
+       dsp_htotal    = dst->hsync_len + dst->left_margin + dst->x_res + dst->right_margin; //dst_htotal ;
+       dsp_hs_end    = dst->hsync_len;
+
+       dsp_vtotal    = dst->vsync_len + dst->upper_margin + dst->y_res + dst->lower_margin;
+       dsp_vs_end    = dst->vsync_len;
+
+       dsp_hbor_end  = dst->hsync_len + dst->left_margin + dst->x_res;
+       dsp_hbor_st   = dst->hsync_len + dst->left_margin  ;
+       dsp_vbor_end  = dst->vsync_len + dst->upper_margin + dst->y_res; //dst_vact_end ;
+       dsp_vbor_st   = dst_vact_st  ;
+
+       dsp_hact_st   = dsp_hbor_st  + bor_left;
+       dsp_hact_end  = dsp_hbor_end - bor_right; 
+       dsp_vact_st   = dsp_vbor_st  + bor_up;
+       dsp_vact_end  = dsp_vbor_end - bor_down; 
+
+       src_w = src->x_res;
+       src_h = src->y_res;
+       dst_w = dsp_hact_end - dsp_hact_st ;
+       dst_h = dsp_vact_end - dsp_vact_st ;
+
+       if(src_w > dst_w)         //ÅжÏhorµÄËõ·Åģʽ 0£ºno_scl 1£ºscl_up 2£ºscl_down
+       {
+               scl_hor_mode = 0x2;   //scl_down
+               if(hor_down_mode == 0)//bilinear
+               {
+                       if((src_w-1)/(dst_w-1) > 2)
+                       {
+                               scl_h_factor = ((src_w-1)<<14)/(dst_w-1);
+                       }
+                       else
+                               scl_h_factor = ((src_w-2)<<14)/(dst_w-1);
+               }
+               else  //average
+               {
+                       scl_h_factor = ((dst_w)<<16)/(src_w-1);
+               }
+       }
+       else if(src_w == dst_w)
+       {
+               scl_hor_mode = 0x0;   //no_Scl
+               scl_h_factor = 0x0;
+       } 
+       else 
+       {
+               scl_hor_mode = 0x1;   //scl_up
+               scl_h_factor = ((src_w-1)<<16)/(dst_w-1);
+       } 
+    
+       if(src_h > dst_h)         //ÅжÏverµÄËõ·Åģʽ 0£ºno_scl 1£ºscl_up 2£ºscl_down
+       {
+               scl_ver_mode = 0x2;   //scl_down
+               if(ver_down_mode == 0)//bilinearhor_down_mode,u8 ver_down_mode
+               {
+                       if((src_h-1)/(dst_h-1) > 2)
+                       {
+                               scl_v_factor = ((src_h-1)<<14)/(dst_h-1);
+                       }
+                       else
+                               scl_v_factor = ((src_h-2)<<14)/(dst_h-1);
+               }
+               else
+               {
+                       scl_v_factor = ((dst_h)<<16)/(src_h-1);
+               }
+       }
+       else if(src_h == dst_h)
+       {
+               scl_ver_mode = 0x0;   //no_Scl
+               scl_v_factor = 0x0;
+       }
+       else 
+       {
+               scl_ver_mode = 0x1;   //scl_up
+               scl_v_factor = ((src_h-1)<<16)/(dst_h-1);
+       }
+
+       //control   register0 
+       scl_reg0_value = (0x1ff<<16) | SCL_EN | (scl_hor_mode<<1) |
+                       (scl_ver_mode<<3) | (bic_coe_sel<<5) | 
+                       (hor_down_mode<<7) | (ver_down_mode<<8) ;
+       //factor    register1 
+       scl_reg1_value = (scl_v_factor << 16) | scl_h_factor ;
+       //dsp_frame register2 
+       scl_reg2_value = dst_frame_vst<<16 | dst_frame_hst ;
+       //dsp_h     register3
+       scl_reg3_value = dsp_hs_end<<16 | dsp_htotal ;
+       //dsp_hact  register4
+       scl_reg4_value = dsp_hact_end <<16 | dsp_hact_st ;
+       //dsp_v     register5
+       scl_reg5_value = dsp_vs_end<<16 | dsp_vtotal ;
+       //dsp_vact  register6
+       scl_reg6_value = dsp_vact_end<<16 | dsp_vact_st ;
+       //hbor      register7
+       scl_reg7_value = dsp_hbor_end<<16 | dsp_hbor_st ;
+       //vbor      register8
+       scl_reg8_value = dsp_vbor_end<<16 | dsp_vbor_st ;
+
+    
+       rk616->write_dev(rk616,SCL_REG0,&scl_reg0_value);  
+       rk616->write_dev(rk616,SCL_REG1,&scl_reg1_value);  
+       rk616->write_dev(rk616,SCL_REG2,&scl_reg2_value);  
+       rk616->write_dev(rk616,SCL_REG3,&scl_reg3_value);  
+       rk616->write_dev(rk616,SCL_REG4,&scl_reg4_value);  
+       rk616->write_dev(rk616,SCL_REG5,&scl_reg5_value);  
+       rk616->write_dev(rk616,SCL_REG6,&scl_reg6_value);  
+       rk616->write_dev(rk616,SCL_REG7,&scl_reg7_value);  
+       rk616->write_dev(rk616,SCL_REG8,&scl_reg8_value);  
+#endif
+       return 0;
+       
+}
+
+
+static int rk616_dual_input_cfg(struct mfd_rk616 *rk616,rk_screen *screen,
+                                       bool enable)
+{
+       struct rk616_platform_data *pdata = rk616->pdata;
+       struct rk616_route *route = &rk616->route;
+       
+       route->vif0_bypass = VIF0_CLK_BYPASS;
+       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(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
+       {
+               route->vif1_bypass  = 0;
+               route->vif1_en      = 1;
+               
+       }
+       else  //hdmi plug out
+       {
+               route->vif1_bypass = VIF1_CLK_BYPASS;
+               route->vif1_en     = 0;
+       }
+
+       route->sclin_sel   = SCL_IN_SEL(SCL_SEL_VIF0); //from vif0
+       route->scl_en      = 0;            //dual lcdc, scaler not needed
+       route->dither_sel  = DITHER_IN_SEL(DITHER_SEL_VIF0); //dither from vif0
+       route->lcd1_input  = 1; 
+       route->lvds_en     = 1;
+
+       if(screen->type == SCREEN_RGB)
+       {
+               route->lvds_mode   = RGB; //rgb output 
+       }
+       else if(screen->type == SCREEN_LVDS)
+       {
+               route->lvds_mode = LVDS;
+               route->lvds_ch_nr = pdata->lvds_ch_nr;
+       }
+       else
+       {
+               dev_err(rk616->dev,"un supported interface:%d\n",screen->type);
+               return -EINVAL;
+       }
+
+       return 0;
+       
+}
+
+static int rk616_lcd0_input_lcd1_unused_cfg(struct mfd_rk616 *rk616,rk_screen *screen,
+                                                       bool enable)
+{
+       struct rk616_platform_data *pdata = rk616->pdata;
+       struct rk616_route *route = &rk616->route;
+       
+       if(enable)  //hdmi plug in
+       {
+               route->vif0_bypass  = 0;
+               route->vif0_en      = 1;
+               route->vif0_clk_sel = VIF0_CLKIN_SEL(VIF_CLKIN_SEL_PLL0);
+               route->sclin_sel    = SCL_IN_SEL(SCL_SEL_VIF0); //from vif0
+               route->scl_en       = 1;
+               route->sclk_sel     = SCLK_SEL(SCLK_SEL_PLL1);
+               route->dither_sel   = DITHER_IN_SEL(DITHER_SEL_SCL); //dither from sclaer
+               route->hdmi_sel     = HDMI_IN_SEL(HDMI_CLK_SEL_VIF0);//from vif0
+               
+       }
+       else
+       {
+               route->vif0_bypass = VIF0_CLK_BYPASS;
+               route->vif0_en     = 0;
+               route->sclin_sel   = SCL_IN_SEL(SCL_SEL_VIF0); //from vif0
+               route->scl_en      = 0;
+               route->dither_sel  = DITHER_IN_SEL(DITHER_SEL_VIF0); //dither from sclaer
+               route->hdmi_sel    = HDMI_IN_SEL(HDMI_CLK_SEL_VIF0);//from vif0
+       }
+       route->pll1_clk_sel = PLL1_CLK_SEL(LCD0_DCLK);
+       route->pll0_clk_sel = PLL0_CLK_SEL(LCD0_DCLK);
+       route->vif1_bypass = VIF1_CLK_BYPASS;
+       route->vif1_en     = 0;
+       route->lcd1_input  = 0;  
+       route->lvds_en     = 1;
+       if(screen->type == SCREEN_RGB)
+       {
+               route->lvds_mode   = RGB; //rgb output 
+       }
+       else if(screen->type == SCREEN_LVDS)
+       {
+               route->lvds_mode = LVDS;
+               route->lvds_ch_nr = pdata->lvds_ch_nr;
+       }
+       else
+       {
+               dev_err(rk616->dev,"un supported interface:%d\n",screen->type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+static int rk616_lcd0_input_lcd1_output_cfg(struct mfd_rk616 *rk616,rk_screen *screen,
+                                                       bool enable)
+{
+       struct rk616_route *route = &rk616->route;
+
+       if(enable)
+       {
+               route->vif0_bypass  = 0;
+               route->vif0_en      = 1;
+               route->vif0_clk_sel = VIF0_CLKIN_SEL(VIF_CLKIN_SEL_PLL0);
+               route->sclin_sel    = SCL_IN_SEL(SCL_SEL_VIF0); //from vif0
+               route->scl_en       = 1;
+               route->sclk_sel     = SCLK_SEL(SCLK_SEL_PLL1);
+               route->dither_sel   = DITHER_IN_SEL(DITHER_SEL_SCL); //dither from sclaer
+               route->hdmi_sel     = HDMI_IN_SEL(HDMI_CLK_SEL_VIF0);//from vif0
+       }
+       else
+       {
+               route->vif0_bypass = VIF0_CLK_BYPASS;
+               route->vif0_en     = 0;
+               route->sclin_sel   = SCL_IN_SEL(SCL_SEL_VIF0); //from vif0
+               route->scl_en      = 0;
+               route->dither_sel  = DITHER_IN_SEL(DITHER_SEL_VIF0); //dither from sclaer
+               route->hdmi_sel    = HDMI_IN_SEL(HDMI_CLK_SEL_VIF0);//from vif0 
+       }
+       route->pll0_clk_sel = PLL0_CLK_SEL(LCD0_DCLK);
+       route->pll1_clk_sel = PLL1_CLK_SEL(LCD0_DCLK);
+       route->vif1_bypass = VIF1_CLK_BYPASS;
+       route->vif1_en = 0;
+       route->lcd1_input = 0; //lcd1 as out put
+       route->lvds_en  = 0;
+
+       return 0;
+       
+}
+
+
+static int rk616_lcd0_unused_lcd1_input_cfg(struct mfd_rk616 *rk616,rk_screen *screen,
+                                                       bool enable)
+{
+       struct rk616_platform_data *pdata = rk616->pdata;
+       struct rk616_route *route = &rk616->route;
+
+       route->pll0_clk_sel = PLL0_CLK_SEL(LCD1_DCLK);
+       route->pll1_clk_sel = PLL1_CLK_SEL(LCD1_DCLK);
+       route->vif0_bypass = VIF0_CLK_BYPASS;
+       route->vif0_en     = 0;
+       route->vif1_bypass = 0;
+       route->vif1_en     = 1;
+       route->vif1_clk_sel = VIF1_CLKIN_SEL(VIF_CLKIN_SEL_PLL1);
+       route->sclin_sel   = SCL_IN_SEL(SCL_SEL_VIF1); //from vif1
+       route->scl_en      = 1;
+       route->sclk_sel    = SCLK_SEL(SCLK_SEL_PLL0);
+       route->scl_bypass  = 1; //1:1 scaler
+       route->dither_sel  = DITHER_IN_SEL(DITHER_SEL_SCL); //dither from sclaer
+       route->hdmi_sel    = HDMI_IN_SEL(HDMI_CLK_SEL_VIF1); //from vif1
+       route->lcd1_input  = 1;  
+       route->lvds_en     = 1;
+       if(screen->type == SCREEN_RGB)
+       {
+               route->lvds_mode   = RGB; //rgb output 
+       }
+       else if(screen->type == SCREEN_LVDS)
+       {
+               route->lvds_mode = LVDS;
+               route->lvds_ch_nr = pdata->lvds_ch_nr;
+       }
+       else
+       {
+               dev_err(rk616->dev,"un supported interface:%d\n",screen->type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int  rk616_set_router(struct mfd_rk616 *rk616,rk_screen *screen,bool enable)
+{
+       struct rk616_platform_data *pdata = rk616->pdata;
+       int ret;
+
+       if((pdata->lcd0_func == INPUT) && (pdata->lcd1_func == INPUT))
+       {
+               
+               ret = rk616_dual_input_cfg(rk616,screen,enable);
+               dev_info(rk616->dev,"rk616 use dual input for dual display!\n");
+       }
+       else if((pdata->lcd0_func == INPUT) && (pdata->lcd1_func == UNUSED))
+       {
+               ret = rk616_lcd0_input_lcd1_unused_cfg(rk616,screen,enable);
+
+               dev_info(rk616->dev,
+                       "rk616 use lcd0 as input and lvds/rgb "
+                       "port as output for dual display\n");
+       }
+       else if((pdata->lcd0_func == INPUT) && (pdata->lcd1_func == OUTPUT))
+       {
+               ret = rk616_lcd0_input_lcd1_output_cfg(rk616,screen,enable);
+               
+               dev_info(rk616->dev,
+                       "rk616 use lcd0 as input and lcd1 as"
+                       "output for dual display\n");
+       }
+       else if((pdata->lcd0_func == UNUSED) && (pdata->lcd1_func == INPUT))
+       {
+               ret = rk616_lcd0_unused_lcd1_input_cfg(rk616,screen,enable);
+               dev_info(rk616->dev,
+                       "rk616 use lcd1 as input and lvds/rgb as"
+                       "output for dual display\n");
+       }
+       else
+       {
+               dev_err(rk616->dev,
+                       "invalid configration,please check your"
+                       "rk616_platform_data setting in your board file!\n");
+               return -EINVAL;
+       }
+
+       return ret ;
+       
+}
+
+
+static int rk616_lvds_cfg(struct mfd_rk616 *rk616,rk_screen *screen)
+{
+       struct rk616_route *route = &rk616->route;
+       u32 val = 0;
+       int ret;
+       
+       if(!route->lvds_en)  //lvds port is not used ,power down lvds
+       {
+               val &= ~(LVDS_CH1TTL_EN | LVDS_CH0TTL_EN | LVDS_CH1_PWR_EN |
+                       LVDS_CH0_PWR_EN | LVDS_CBG_PWR_EN);
+               val |= LVDS_PLL_PWR_DN | (LVDS_CH1TTL_EN << 16) | (LVDS_CH0TTL_EN << 16) |
+                       (LVDS_CH1_PWR_EN << 16) | (LVDS_CH0_PWR_EN << 16) |
+                       (LVDS_CBG_PWR_EN << 16) | (LVDS_PLL_PWR_DN << 16);
+               ret = rk616->write_dev(rk616,CRU_LVDS_CON0,&val);
+
+               if(!route->lcd1_input)  //set lcd1 port for output as RGB interface
+               {
+                       val = (LCD1_INPUT_EN << 16);
+                       ret = rk616->write_dev(rk616,CRU_IO_CON0,&val);
+               }
+       }
+       else
+       {
+               if(route->lvds_mode)  //lvds mode
+               {
+
+                       if(route->lvds_ch_nr == 2) //dual lvds channel
+                       {
+                               val &= ~(LVDS_CH0TTL_EN | LVDS_CH1TTL_EN);
+                               val = (LVDS_DCLK_INV)  | (LVDS_CH1_PWR_EN) |(LVDS_CH0_PWR_EN) | 
+                                       (LVDS_CBG_PWR_EN) | (LVDS_CH_SEL) | (LVDS_OUT_FORMAT(screen->hw_format)) | 
+                                       (LVDS_CH0TTL_EN << 16) | (LVDS_CH1TTL_EN << 16) |(LVDS_CH1_PWR_EN << 16) | 
+                                       (LVDS_CH0_PWR_EN << 16) | (LVDS_CBG_PWR_EN << 16) | (LVDS_CH_SEL << 16) | 
+                                       (LVDS_OUT_FORMAT_MASK);
+                               ret = rk616->write_dev(rk616,CRU_LVDS_CON0,&val);
+                               
+                               dev_info(rk616->dev,"rk616 use dual lvds channel.......\n");
+                       }
+                       else //single lvds channel
+                       {
+                               val = 0;
+                               val &= ~(LVDS_CH0TTL_EN | LVDS_CH1TTL_EN | LVDS_CH1_PWR_EN | LVDS_PLL_PWR_DN | LVDS_CH_SEL); //use channel 0
+                               val |= (LVDS_CH0_PWR_EN) |(LVDS_CBG_PWR_EN) | (LVDS_OUT_FORMAT(screen->hw_format)) | 
+                                     (LVDS_CH0TTL_EN << 16) | (LVDS_CH1TTL_EN << 16) |(LVDS_CH0_PWR_EN << 16) | 
+                                      (LVDS_DCLK_INV ) | (LVDS_CH0TTL_EN << 16) | (LVDS_CH1TTL_EN << 16) |(LVDS_CH0_PWR_EN << 16) | 
+                                       (LVDS_CBG_PWR_EN << 16)|(LVDS_CH_SEL << 16) | (LVDS_PLL_PWR_DN << 16)| 
+                                      (LVDS_OUT_FORMAT_MASK) | (LVDS_DCLK_INV << 16);
+                               ret = rk616->write_dev(rk616,CRU_LVDS_CON0,&val);
+
+                               dev_info(rk616->dev,"rk616 use single lvds channel.......\n");
+                               
+                       }
+
+               }
+               else //mux lvds port to RGB mode
+               {
+                       val &= ~(LVDS_CBG_PWR_EN| LVDS_CH1_PWR_EN | LVDS_CH0_PWR_EN);
+                       val |= (LVDS_CH0TTL_EN)|(LVDS_CH1TTL_EN )|(LVDS_PLL_PWR_DN)|
+                               (LVDS_CH0TTL_EN<< 16)|(LVDS_CH1TTL_EN<< 16)|(LVDS_CH1_PWR_EN << 16) | 
+                               (LVDS_CH0_PWR_EN << 16)|(LVDS_CBG_PWR_EN << 16)|(LVDS_PLL_PWR_DN << 16);
+                       ret = rk616->write_dev(rk616,CRU_LVDS_CON0,&val);
+
+                       val &= ~(LVDS_OUT_EN);
+                       val |= (LVDS_OUT_EN << 16);
+                       ret = rk616->write_dev(rk616,CRU_IO_CON0,&val);
+                       dev_info(rk616->dev,"rk616 use RGB output.....\n");
+                       
+               }
+       }
+
+       return 0;
+       
+}
+static int rk616_display_router_cfg(struct mfd_rk616 *rk616,rk_screen *screen,bool enable)
+{
+       u32 val = 0;
+       int ret;
+       struct rk616_route *route = &rk616->route;
+
+       
+       ret = rk616_set_router(rk616,screen,enable);
+       if(ret < 0)
+               return ret;
+
+       
+       val = (route->pll0_clk_sel) | (route->pll1_clk_sel) |
+               PLL1_CLK_SEL_MASK | PLL0_CLK_SEL_MASK; //pll1 clk from lcdc1_dclk,pll0 clk from lcdc0_dclk,mux_lcdx = lcdx_clk
+       ret = rk616->write_dev(rk616,CRU_CLKSEL0_CON,&val);
+       
+       val = (route->sclk_sel) | SCLK_SEL_MASK;
+       ret = rk616->write_dev(rk616,CRU_CLKSEL1_CON,&val);
+       
+       val = (SCL_IN_SEL_MASK) | (DITHER_IN_SEL_MASK) | (HDMI_IN_SEL_MASK) | 
+               (VIF1_CLKIN_SEL_MASK) | (VIF0_CLKIN_SEL_MASK) | (VIF1_CLK_BYPASS << 16) | 
+               (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);
+       
+       if((screen->type == SCREEN_RGB) || (screen->type == SCREEN_LVDS))
+       {
+               rk616_lvds_cfg(rk616,screen);
+       }       
+       
+       
+       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);
+       else
+               val |= (FRC_DITHER_EN << 16);
+       ret = rk616->write_dev(rk616,FRC_REG,&val);
+       
+       ret = rk616_vif_cfg(rk616,screen,0);
+       ret = rk616_vif_cfg(rk616,screen,1);
+       ret = rk616_scaler_cfg(rk616,screen);
+
+       return 0;
+       
+}
+
+int rk610_lcd_scaler_set_param(rk_screen *screen,bool enable )//enable:0 bypass 1: scale
+{
+       int ret;
+       struct mfd_rk616 *rk616 = g_rk616;
+       if(!rk616)
+       {
+               printk(KERN_ERR "%s:mfd rk616 is null!\n",__func__);
+               return -1;
+       }
+       ret = rk616_display_router_cfg(rk616,screen,enable);
+       return ret;
+}
+
+static int rk616_vif_probe(struct platform_device *pdev)
+{
+
+       struct mfd_rk616 *rk616 = dev_get_drvdata(pdev->dev.parent);
+       if(!rk616)
+       {
+               dev_err(&pdev->dev,"null mfd device rk616!\n");
+               return -ENODEV;
+       }
+       else
+               g_rk616 = rk616;
+       
+
+       dev_info(&pdev->dev,"rk616 vif probe success!\n");
+
+       return 0;
+       
+}
+
+static int rk616_vif_remove(struct platform_device *pdev)
+{
+       
+       return 0;
+}
+
+static void rk616_vif_shutdown(struct platform_device *pdev)
+{
+       
+       return;
+}
+
+static struct platform_driver rk616_lvds_driver = {
+       .driver         = {
+               .name   = "rk616-vif",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = rk616_vif_probe,
+       .remove         = rk616_vif_remove,
+       .shutdown       = rk616_vif_shutdown,
+};
+
+static int __init rk616_lvds_init(void)
+{
+       return platform_driver_register(&rk616_lvds_driver);
+}
+subsys_initcall_sync(rk616_lvds_init);
+
+static void __exit rk616_lvds_exit(void)
+{
+       platform_driver_unregister(&rk616_lvds_driver);
+}
+module_exit(rk616_lvds_exit);
+
index 6832956f9b04f213432210615b68973e1d54ecda..ff72bf2df62b01626660ab7157c6faba3ac6dcff 100644 (file)
@@ -41,6 +41,7 @@
 #define FRC_RGB18_MODE         (1<<2)
 #define FRC_HIFRC_MODE         (1<<1)
 #define FRC_DITHER_EN          (1<<0)
+
 #define CRU_CLKSEL0_CON        0x0058
 #define PLL1_CLK_SEL_MASK      (0x3<<24)
 #define PLL0_CLK_SEL_MASK      (0x3<<22)
 #define LCD0_CLK_DIV_MASK      (0x7<<16)
 #define PLL1_CLK_SEL(x)        (((x)&3)<<8)
 #define PLL0_CLK_SEL(x)        (((x)&3)<<6)
+#define LCD0_DCLK              0
+#define LCD1_DCLK              1
+#define MCLK_12M               2
 #define LCD1_CLK_DIV(x)        (((x)&7)<<3)
 #define LCD0_CLK_DIV(x)        (((x)&7)<<0)
 
 #define CRU_CLKSEL1_CON        0x005C
+#define SCLK_SEL_MASK          (1<<19)
 #define CODEC_MCLK_SEL_MASK    (3<<16)
 #define LCDC_CLK_GATE          (1<<12)
 #define LCDC1_CLK_GATE         (1<<11)
 #define HDMI_CLK_GATE          (1<<8)
 #define SCL_CLK_DIV(x)         (((x)&7)<<5)
 #define SCL_CLK_GATE           (1<<4)
-#define SCL_CLK_IN_SEL         (1<<3)
+#define SCLK_SEL(x)            (((x)&1)<<3)
+#define SCLK_SEL_PLL0          0
+#define SCLK_SEL_PLL1          1
 #define CODEC_CLK_GATE         (1<<2)
 #define CODEC_MCLK_SEL(x)      (((x)&3)<<0)
+#define CODEC_MCLK_SEL_PLL0    0
+#define CODEC_MCLK_SEL_PLL1    1
+#define CODEC_MCLK_SEL_12M     2
 
 #define CRU_CODEC_DIV          0x0060
 
 #define CRU_CLKSE2_CON         0x0064
-#define HDMI_CLK_SEL_MASK      (3<<28)
+#define SCL_IN_SEL_MASK                (1<<31)
+#define DITHER_IN_SEL_MASK     (1<<30)
+#define HDMI_IN_SEL_MASK       (3<<28)
 #define VIF1_CLK_DIV_MASK      (7<<25)
 #define VIF0_CLK_DIV_MASK      (7<<19)
-#define SCLIN_CLK_SEL          (1<<15)
-#define SCL_SEL_VIF0           0
-#define SCL_SEL_VIF1           1
-#define DITHER_CLK_SEL         (1<<14)
+#define VIF1_CLKIN_SEL_MASK    (1<<22)
+#define VIF0_CLKIN_SEL_MASK    (1<<16)
+#define SCL_IN_SEL(x)          (((x)&1)<<15)
+#define SCL_SEL_VIF0                   0
+#define SCL_SEL_VIF1                   1
+#define DITHER_IN_SEL(x)       (((x)&1)<<14)
 #define DITHER_SEL_VIF0                0
 #define DITHER_SEL_SCL         1
 
-#define HDMI_CLK_SEL(x)                (((x)&3)<<12)
+#define HDMI_IN_SEL(x)         (((x)&3)<<12)
+#define HDMI_CLK_SEL_VIF1      0
+#define HDMI_CLK_SEL_SCL       1
+#define HDMI_CLK_SEL_VIF0      2
 #define VIF1_CLK_DIV(x)        (((x)&7)<<9)
 #define VIF1_CLK_GATE          (1<<8)
 #define VIF1_CLK_BYPASS                (1<<7)
-#define VIF1_CLK_SEL           (1<<6)
+#define VIF1_CLKIN_SEL(x)      (((x)&1)<<6)
+#define VIF_CLKIN_SEL_PLL0     0
+#define VIF_CLKIN_SEL_PLL1     1
 #define VIF0_CLK_DIV(x)                (((x)&7)<<3)
 #define VIF0_CLK_GATE          (1<<2)
 #define VIF0_CLK_BYPASS                (1<<1)
-#define VIF0_CLK_SEL           (1<<0)
+#define VIF0_CLKIN_SEL(x)      (((x)&1)<<0)
+
 
 #define CRU_PLL0_CON0          0x0068
 #define PLL0_POSTDIV1_MASK     (7<<28)
 #define PLL0_FOUTVCO_PWR_DN    (1<<26)
 #define PLL0_POSTDIV_PWR_DN    (1<<25)
 #define PLL0_DAC_PWR_DN                (1<<24)
-#define PLL0_FRAC(x)           (((x)&0xffffff)<0)
+#define PLL0_FRAC(x)           (((x)&0xffffff)<<0)
 
 #define CRU_PLL1_CON0          0x0074
 #define PLL1_POSTDIV1_MASK     (7<<28)
@@ -194,6 +214,10 @@ enum lcd_port_func{       // the function of lcd ports(lcd0,lcd1),the lcd0 only
        OUTPUT,
 };
 
+enum lvds_mode {
+       RGB,
+       LVDS,
+};
 struct rk616_platform_data {
        int (*power_init)(void);
        int scl_rate;
@@ -205,17 +229,23 @@ struct rk616_platform_data {
 };
 
 struct rk616_route {
-       u8 vif0_bypass;
-       u8 vif0_en;
-       u8 vif1_bypass;
-       u8 vif1_en;
-       u8 sclin_sel;
-       u8 scl_en;
-       u8 dither_sel;
-       u8 hdmi_sel;
-       u8 lcd1_input;
-       u8 lvds_en;
-       u8 lvds_mode;                //RGB or LVDS
+       u16 vif0_bypass;
+       u8  vif0_en;
+       u16 vif0_clk_sel;
+       u16 vif1_bypass;
+       u8  vif1_en;
+       u16 vif1_clk_sel;
+       u16 sclin_sel;
+       u8  scl_en;
+       u8  scl_bypass;
+       u16 dither_sel;
+       u16 hdmi_sel;
+       u16 pll0_clk_sel;
+       u16 pll1_clk_sel;
+       u16 sclk_sel;
+       u8  lcd1_input;
+       u8  lvds_en;
+       enum lvds_mode lvds_mode;                //RGB or LVDS
        int lvds_ch_nr;         //the number of used  lvds channel 
 };