From 0ae1d938a4ecfc1e8a8e676b21770871899f4b7b Mon Sep 17 00:00:00 2001 From: yxj Date: Thu, 18 Apr 2013 22:22:22 +0800 Subject: [PATCH] mfd:rk616:lvds function ok --- drivers/mfd/rk616-core.c | 77 +++ .../video/display/transmitter/rk616_lvds.c | 445 +++++++++++++++--- include/linux/mfd/rk616.h | 31 +- 3 files changed, 491 insertions(+), 62 deletions(-) diff --git a/drivers/mfd/rk616-core.c b/drivers/mfd/rk616-core.c index 7dbd7ea44799..44e85ae5b427 100644 --- a/drivers/mfd/rk616-core.c +++ b/drivers/mfd/rk616-core.c @@ -15,6 +15,9 @@ #include #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 diff --git a/drivers/video/display/transmitter/rk616_lvds.c b/drivers/video/display/transmitter/rk616_lvds.c index 84a68919bb10..e5d162672420 100644 --- a/drivers/video/display/transmitter/rk616_lvds.c +++ b/drivers/video/display/transmitter/rk616_lvds.c @@ -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"); diff --git a/include/linux/mfd/rk616.h b/include/linux/mfd/rk616.h index 68b9637193bf..df5bad7b2791 100644 --- a/include/linux/mfd/rk616.h +++ b/include/linux/mfd/rk616.h @@ -34,7 +34,13 @@ #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) @@ -112,12 +121,13 @@ #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) @@ -125,7 +135,7 @@ #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 @@ -162,11 +172,18 @@ #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); -- 2.34.1