mfd:rk616:lvds function ok
authoryxj <yxj@rock-chips.com>
Thu, 18 Apr 2013 14:22:22 +0000 (22:22 +0800)
committeryxj <yxj@rock-chips.com>
Thu, 18 Apr 2013 14:46:35 +0000 (22:46 +0800)
drivers/mfd/rk616-core.c
drivers/video/display/transmitter/rk616_lvds.c
include/linux/mfd/rk616.h

index 7dbd7ea44799c94fe0efc7cfccc0578462355855..44e85ae5b4276886b58bd981473bdb3573cb1322 100644 (file)
@@ -15,6 +15,9 @@
 #include <linux/seq_file.h>
 #endif
 
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
 
 static struct mfd_cell rk616_devs[] = {
        {
@@ -145,6 +148,80 @@ static const struct file_operations rk616_reg_fops = {
 };
 #endif
 
+
+static u32 rk616_clk_gcd(u32 numerator, u32 denominator)
+{
+       u32 a, b;
+
+       if (!numerator || !denominator)
+               return 0;
+
+       if (numerator > denominator) {
+               a = numerator;
+               b = denominator;
+       } else {
+               a = denominator;
+               b = numerator;
+       }
+
+       while (b != 0) {
+               int r = b;
+               b = a % b;
+               a = r;
+       }
+
+       return a;
+}
+
+
+static int rk616_pll_clk_get_set(struct mfd_rk616 *rk616,unsigned long fin_hz,unsigned long fout_hz,
+                                       u32 *refdiv, u32 *fbdiv, u32 *postdiv1, u32 *postdiv2, u32 *frac)
+{
+       // FIXME set postdiv1/2 always 1        
+       u32 gcd;
+       u64 fin_64, frac_64;
+       u32 f_frac;
+       if(!fin_hz || !fout_hz || fout_hz == fin_hz)
+               return -1;
+
+       if(fin_hz / MHZ * MHZ == fin_hz && fout_hz /MHZ * MHZ == fout_hz)
+       {
+               fin_hz /= MHZ;
+               fout_hz /= MHZ;
+               gcd = rk616_clk_gcd(fin_hz, fout_hz);
+               *refdiv = fin_hz / gcd;
+               *fbdiv = fout_hz / gcd;
+               *postdiv1 = 1;
+               *postdiv2 = 1;
+
+               *frac = 0;
+
+               dev_info(rk616->dev,"fin=%lu,fout=%lu,gcd=%u,refdiv=%u,fbdiv=%u,postdiv1=%u,postdiv2=%u,frac=%u\n",
+                               fin_hz, fout_hz, gcd, *refdiv, *fbdiv, *postdiv1, *postdiv2, *frac);
+       } 
+       else 
+       {
+               dev_info(rk616->dev,"******frac div running, fin_hz=%lu, fout_hz=%lu, fin_mhz=%lu, fout_mhz=%lu\n",
+                               fin_hz, fout_hz, fin_hz / MHZ * MHZ, fout_hz / MHZ * MHZ);
+               gcd = rk616_clk_gcd(fin_hz / MHZ, fout_hz / MHZ);
+               *refdiv = fin_hz / MHZ / gcd;
+               *fbdiv = fout_hz / MHZ / gcd;
+               *postdiv1 = 1;
+               *postdiv2 = 1;
+
+               *frac = 0;
+
+               f_frac = (fout_hz % MHZ);
+               fin_64 = fin_hz;
+               do_div(fin_64, (u64)*refdiv);
+               frac_64 = (u64)f_frac << 24;
+               do_div(frac_64, fin_64);
+               *frac = (u32) frac_64;
+               dev_dbg(rk616->dev,"frac_64=%llx, frac=%u\n", frac_64, *frac);
+       }
+       return 0;
+}
+
 /***********************************
 default clk patch settiing:
 CLKIN-------->CODEC
index 84a68919bb102387519c9dbfc0f0ae4af56a45d9..e5d162672420a7133ea985ce78251bd524ab40a5 100644 (file)
@@ -7,24 +7,6 @@
 
 struct mfd_rk616 *g_rk616;
 
-
-/********************************************
-LCDC1------>HDMI
-LCDC0------>Dither------->LVDS/MIPI
-*********************************************/
-static struct rk616_route rk616_route = {
-       .vif0_bypass = 1,
-       .vif0_en     = 0,
-       .vif1_bypass = 1,
-       .vif1_en     = 0,
-       .sclin_sel   = 0,
-       .scl_en      = 0,
-       .dither_sel  = 0,
-       .hdmi_sel    = 0,
-       .lcd1_input  = 1,
-       .lvds_mode   = 1, //lvds out put 
-};
-
 /*rk616 video interface config*/
 static int rk616_vif_cfg(struct mfd_rk616 *rk616,rk_screen *screen,int id)
 {
@@ -33,17 +15,27 @@ static int rk616_vif_cfg(struct mfd_rk616 *rk616,rk_screen *screen,int id)
        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) & (~VIF0_DDR_PHASEN_EN) & (~VIF0_DDR_MODE_EN))|
-               (VIF0_EN);
        val |= (VIF0_DDR_CLK_EN <<16) | (VIF0_DDR_PHASEN_EN << 16) | (VIF0_DDR_MODE_EN << 16)|
-               (VIF0_EN <<16);
+               (VIF0_EN <<16) | VIF0_EN; //disable ddr mode,enable VIF
        
        ret = rk616->write_dev(rk616,VIF0_REG0 + offset,&val);  
 
@@ -72,61 +64,403 @@ static int rk616_vif_cfg(struct mfd_rk616 *rk616,rk_screen *screen,int id)
        
 }
 
-static int rk616_vif_disable(struct mfd_rk616 *rk616,int id)
+
+
+static int rk616_scaler_cfg(struct mfd_rk616 *rk616,rk_screen *screen)
 {
-       int ret;
        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;
+
+       double fk = 1.0;
+       struct rk616_route *route = &rk616->route;
+#if 0
+       rk_screen *src = screen->ext_screen;
+       rk_screen *dst = screen;
+       u32 DCLK_IN = src->pixclock;
+#endif
 
-       val &= (~VIF0_EN);
-       val |= (VIF0_EN << 16);
-       if(id == 0)
+       if(!route->scl_en)
        {
-               ret = rk616->write_dev(rk616,VIF0_REG0,&val);
+               val &= (~SCL_EN);       //disable scaler
+               val |= (SCL_EN<<16);
+               ret = rk616->write_dev(rk616,SCL_REG0,&val);
+               return 0;
        }
-       else
+       
+
+#if 0
+
+       src_htotal = src->hsync_len + src->left_margin + src->x_res + src->right_margin;
+       src_vact_st = src->hsync_len + src->left_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)
        {
-               ret = rk616->write_dev(rk616,VIF1_REG0,&val);
+               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
 
-       return ret;
+       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_scaler_disable(struct mfd_rk616 *rk616)
+static int  rk616_set_router(struct mfd_rk616 *rk616,rk_screen *screen)
 {
-       u32 val = 0;
-       int ret;
+       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;
+               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;
+               }
+               else
+               {
+                       dev_err(rk616->dev,"un supported interface:%d\n",screen->type);
+                       return -EINVAL;
+               }
+                       
+               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))
+       {
+               if(screen->type == SCREEN_RGB)
+               {
+                       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 = 1;
+                       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
+               {
+                       dev_err(rk616->dev,"rk616 lcd1 only support RGB port in output mode\n");
+                       return -EINVAL;
+               }
+       }
+       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");   
+       }
 
-       val &= (~SCL_EN);       //disable scaler
-       val |= (SCL_EN<<16);
-       ret = rk616->write_dev(rk616,SCL_REG0,&val);
-       
        return 0;
        
 }
-
-
-static int rk616_display_router_cfg(struct mfd_rk616 *rk616)
+static int rk616_display_router_cfg(struct mfd_rk616 *rk616,rk_screen *screen)
 {
        u32 val = 0;
        int ret;
-       struct rk616_route *route = rk616->route;
+       struct rk616_route *route = &rk616->route;
+
+       
+
+       ret = rk616_set_router(rk616,screen);
+       if(ret < 0)
+               return ret;
        
-       val = (0xffff<<16) | (route->sclin_sel<<15) | (route->dither_sel<<14) | 
-               (route->hdmi_sel<<12) | (route->vif1_bypass<<7) | 
-               (route->vif0_bypass<<1) ; 
+       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);
 
-       val = (LVDS_CH0TTL_DISABLE) | (LVDS_CH1TTL_DISABLE) | (LVDS_CH0_PWR_EN) |
-               (LVDS_CBG_PWR_EN) | (LVDS_CH0TTL_DISABLE << 16) | (LVDS_CH1TTL_DISABLE << 16) |
-               (LVDS_CH0_PWR_EN << 16) | (LVDS_CBG_PWR_EN << 16);
-       ret = rk616->write_dev(rk616,CRU_LVDS_CON0,&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);
+                       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 &= ~(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_CBG_PWR_EN << 16)|(LVDS_CH_SEL << 16) | (LVDS_PLL_PWR_DN << 16)| 
+                                       (LVDS_OUT_FORMAT_MASK);
+                               ret = rk616->write_dev(rk616,CRU_LVDS_CON0,&val);
+                               
+                               dev_info(rk616->dev,"rk616 use single lvds channel.......\n");
+                       }
+
+                       val = FRC_DCLK_INV | (FRC_DCLK_INV << 16);
+                       ret = rk616->write_dev(rk616,FRC_REG,&val);
+                       
+                       
+               
+               }
+               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");
+                       
+               }
+       }
        
-       if(!route->vif0_en)
-               rk616_vif_disable(rk616,0); //disable vif0 
-       if(!route->vif1_en)
-               rk616_vif_disable(rk616,1); //disable vif1
-       if(!route->scl_en)
-               rk616_scaler_disable(rk616);
+       
+       
+       ret = rk616_vif_cfg(rk616,screen,0);
+       ret = rk616_vif_cfg(rk616,screen,1);
+       ret = rk616_scaler_cfg(rk616,screen);
 
        return 0;
        
@@ -140,7 +474,7 @@ int rk610_lcd_scaler_set_param(rk_screen *screen,bool enable )//enable:0 bypass
                printk(KERN_ERR "%s:mfd rk616 is null!\n",__func__);
                return -1;
        }
-       rk616_display_router_cfg(rk616);
+       rk616_display_router_cfg(rk616,screen);
        return ret;
 }
 
@@ -156,7 +490,6 @@ static int rk616_lvds_probe(struct platform_device *pdev)
        else
                g_rk616 = rk616;
        
-       rk616->route = &rk616_route;
 
        dev_info(&pdev->dev,"rk616 lvds probe success!\n");
 
index 68b9637193bf13dd927410b6a8b01f869112f72d..df5bad7b2791e10341590825517ac9d0bd8fa43b 100644 (file)
 #define SCL_REG7               0x004C
 #define SCL_REG8               0x0050
 #define FRC_REG                0x0054
-
+#define FRC_DEN_INV            (1<<6)
+#define FRC_SYNC_INV           (1<<5)
+#define FRC_DCLK_INV           (1<<4)
+#define FRC_OUT_ZERO           (1<<3)
+#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)
@@ -61,6 +67,9 @@
 #define CRU_CODEC_DIV          0x0060
 
 #define CRU_CLKSE2_CON         0x0064
+#define HDMI_CLK_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 DITHER_CLK_SEL         (1<<14)
 #define HDMI_CLK_SEL(x)                (((x)&3)<<12)
 #define CRU_I2C_CON0           0x0080
 
 #define CRU_LVDS_CON0          0x0084
+#define LVDS_OUT_FORMAT_MASK   (3<<16)
 #define LVDS_CON_ST_PHASE      (1<<14)
 #define LVDS_DCLK_INV          (1<<13)
 #define LVDS_CH1_LOAD          (1<<12)
 #define LVDS_CH0_LOAD          (1<<11)
-#define LVDS_CH1TTL_DISABLE    (1<<10)
-#define LVDS_CH0TTL_DISABLE    (1<<9)
+#define LVDS_CH1TTL_EN                 (1<<10)
+#define LVDS_CH0TTL_EN                 (1<<9)
 #define LVDS_CH1_PWR_EN                (1<<8)
 #define LVDS_CH0_PWR_EN                (1<<7)
 #define LVDS_CBG_PWR_EN                (1<<6)
 #define LVDS_START_CH_SEL      (1<<4)
 #define LVDS_CH_SEL            (1<<3)
 #define LVDS_MSB_SEL           (1<<2)
-#define LVDS_OUT_FORMAT                (1<<0)
+#define LVDS_OUT_FORMAT(x)     (((x)&3)<<0)
 
 
 #define CRU_IO_CON0                    0x0088
 #define CRU_CFGMISC_CON                0x009C
 
 
-
+enum lcd_port_func{       // the function of lcd ports(lcd0,lcd1),the lcd0 only can be used as input or unused
+       UNUSED,             // the lcd1 can be used as input,output or unused
+       INPUT,
+       OUTPUT,
+};
 
 struct rk616_platform_data {
        int (*power_init)(void);
        int scl_rate;
+       enum lcd_port_func lcd0_func;
+       enum lcd_port_func lcd1_func;
+       int lvds_ch_nr;                 //the number of used  lvds channel 
 };
 
 struct rk616_route {
@@ -179,7 +196,9 @@ struct rk616_route {
        u8 dither_sel;
        u8 hdmi_sel;
        u8 lcd1_input;
+       u8 lvds_en;
        u8 lvds_mode;                //RGB or LVDS
+       int lvds_ch_nr;         //the number of used  lvds channel 
 };
 
 struct mfd_rk616 {
@@ -188,7 +207,7 @@ struct mfd_rk616 {
        struct device *dev;
        unsigned int irq_base;
        struct rk616_platform_data *pdata;
-       struct rk616_route *route;  //display path router
+       struct rk616_route route;  //display path router
        struct i2c_client *client;
        struct dentry *debugfs_dir;
        int (*read_dev)(struct mfd_rk616 *rk616,u16 reg,u32 *pval);