1 #include <linux/kernel.h>
2 #include <linux/init.h>
3 #include <linux/platform_device.h>
4 #include <linux/slab.h>
5 #include <linux/mfd/rk616.h>
8 extern int rk616_pll_set_rate(struct mfd_rk616 *rk616,int id,u32 cfg_val,u32 frac);
10 /*rk616 video interface config*/
11 int rk616_vif_cfg(struct mfd_rk616 *rk616,rk_screen *screen,int id)
17 bool pll_use_mclk12m = false;
19 if(id == 0) //video interface 0
21 if(!rk616->route.vif0_en)
23 val = (VIF0_EN << 16); //disable vif0
24 ret = rk616->write_dev(rk616,VIF0_REG0,&val);
25 clk_set_rate(rk616->mclk, 11289600);
29 pll_id = rk616->route.vif0_clk_sel;
30 if(rk616->route.pll0_clk_sel == PLL0_CLK_SEL(MCLK_12M))
31 pll_use_mclk12m = true;
33 pll_use_mclk12m = false;
35 else //vide0 interface 1
37 if(!rk616->route.vif1_en)
39 val = (VIF0_EN << 16); //disabl VIF1
40 ret = rk616->write_dev(rk616,VIF1_REG0,&val);
41 clk_set_rate(rk616->mclk, 11289600);
45 pll_id = (rk616->route.vif1_clk_sel >> 6);
46 if(rk616->route.pll1_clk_sel == PLL1_CLK_SEL(MCLK_12M))
47 pll_use_mclk12m = true;
49 pll_use_mclk12m = false;
54 clk_set_rate(rk616->mclk, 12000000);
60 dev_err(rk616->dev,"%s:screen is null.........\n",__func__);
66 val |= (VIF0_DDR_CLK_EN <<16) | (VIF0_DDR_PHASEN_EN << 16) | (VIF0_DDR_MODE_EN << 16)|
67 (VIF0_EN <<16) | VIF0_EN; //disable ddr mode,enable VIF
69 ret = rk616->write_dev(rk616,VIF0_REG0 + offset,&val);
71 if( (screen->x_res == 1920) && (screen->y_res == 1080))
74 rk616_pll_set_rate(rk616,pll_id,0xc11025,0x200000);
76 rk616_pll_set_rate(rk616,pll_id,0x02bf5276,0);
78 else if((screen->x_res == 1280) && (screen->y_res == 720))
81 rk616_pll_set_rate(rk616,pll_id,0x01811025,0x200000);
83 rk616_pll_set_rate(rk616,pll_id,0x1422014,0);
85 else if((screen->x_res == 720))
88 rk616_pll_set_rate(rk616,pll_id,0x01413021,0xc00000);
90 rk616_pll_set_rate(rk616,pll_id,0x1c13015,0);
93 //val = fscreen->vif_hst | (fscreen->vif_vst<<16);
94 val = (0xc1) | (0x01 <<16);
95 ret = rk616->write_dev(rk616,VIF0_REG1 + offset,&val);
97 val = (screen->hsync_len << 16) | (screen->hsync_len + screen->left_margin +
98 screen->right_margin + screen->x_res);
99 ret = rk616->write_dev(rk616,VIF0_REG2 + offset,&val);
102 val = ((screen->hsync_len + screen->left_margin + screen->x_res)<<16) |
103 (screen->hsync_len + screen->left_margin);
104 ret = rk616->write_dev(rk616,VIF0_REG3 + offset,&val);
106 val = (screen->vsync_len << 16) | (screen->vsync_len + screen->upper_margin +
107 screen->lower_margin + screen->y_res);
108 ret = rk616->write_dev(rk616,VIF0_REG4 + offset,&val);
111 val = ((screen->vsync_len + screen->upper_margin + screen->y_res)<<16) |
112 (screen->vsync_len + screen->upper_margin);
113 ret = rk616->write_dev(rk616,VIF0_REG5 + offset,&val);
120 static int rk616_vif_disable(struct mfd_rk616 *rk616,int id)
125 printk(KERN_INFO "rk616 vif%d disable\n",id);
127 if(id == 0) //video interface 0
130 val = (VIF0_EN << 16); //disable vif0
131 ret = rk616->write_dev(rk616,VIF0_REG0,&val);
132 clk_set_rate(rk616->mclk, 11289600);
136 else //vide0 interface 1
139 val = (VIF0_EN << 16); //disabl VIF1
140 ret = rk616->write_dev(rk616,VIF1_REG0,&val);
141 clk_set_rate(rk616->mclk, 11289600);
148 static int rk616_scaler_disable(struct mfd_rk616 *rk616)
152 val &= (~SCL_EN); //disable scaler
154 ret = rk616->write_dev(rk616,SCL_REG0,&val);
157 int rk616_scaler_cfg(struct mfd_rk616 *rk616,rk_screen *screen)
161 u32 scl_hor_mode,scl_ver_mode;
162 u32 scl_v_factor,scl_h_factor;
163 u32 scl_reg0_value,scl_reg1_value,scl_reg2_value; //scl_con,scl_h_factor,scl_v_factor,
164 u32 scl_reg3_value,scl_reg4_value,scl_reg5_value,scl_reg6_value; //dsp_frame_hst,dsp_frame_vst,dsp_timing,dsp_act_timing
165 u32 scl_reg7_value,scl_reg8_value; //dsp_hbor ,dsp_vbor
166 u32 dst_frame_hst,dst_frame_vst; //ʱÐò»º´æ
167 u32 dst_htotal,dst_hs_end,dst_hact_st,dst_hact_end; //ÆÁÄ»typical h²ÎÊý
168 u32 dst_vtotal,dst_vs_end,dst_vact_st,dst_vact_end; //ÆÁÄ»typical v²ÎÊý
170 u32 dsp_htotal,dsp_hs_end,dsp_hact_st,dsp_hact_end; //scalerÊä³öµÄtiming²ÎÊý
171 u32 dsp_vtotal,dsp_vs_end,dsp_vact_st,dsp_vact_end;
172 u32 dsp_hbor_end,dsp_hbor_st,dsp_vbor_end,dsp_vbor_st;
173 u32 src_w,src_h,src_htotal,src_vtotal,dst_w,dst_h,src_hact_st,src_vact_st;
178 u8 hor_down_mode = 0; //1:average,0:bilinear
179 u8 ver_down_mode = 0;
185 struct rk616_route *route = &rk616->route;
190 rk616_scaler_disable(rk616);
198 dev_err(rk616->dev,"%s:screen is null!\n",__func__);
202 if(route->scl_bypass)
205 dst->pll_cfg_val = 0x01422014;
209 src = screen->ext_screen;
211 if(route->sclk_sel == SCLK_SEL(SCLK_SEL_PLL0))
215 rk616_pll_set_rate(rk616,pll_id,dst->pll_cfg_val,dst->frac);
216 dst_frame_vst = dst->scl_vst;
217 dst_frame_hst = dst->scl_hst;
222 src_htotal = src->hsync_len + src->left_margin + src->x_res + src->right_margin;
223 src_vact_st = src->vsync_len + src->upper_margin ;
224 dst_vact_st = dst->vsync_len + dst->upper_margin;
226 dsp_htotal = dst->hsync_len + dst->left_margin + dst->x_res + dst->right_margin; //dst_htotal ;
227 dsp_hs_end = dst->hsync_len;
229 dsp_vtotal = dst->vsync_len + dst->upper_margin + dst->y_res + dst->lower_margin;
230 dsp_vs_end = dst->vsync_len;
232 dsp_hbor_end = dst->hsync_len + dst->left_margin + dst->x_res;
233 dsp_hbor_st = dst->hsync_len + dst->left_margin ;
234 dsp_vbor_end = dst->vsync_len + dst->upper_margin + dst->y_res; //dst_vact_end ;
235 dsp_vbor_st = dst_vact_st ;
237 dsp_hact_st = dsp_hbor_st + bor_left;
238 dsp_hact_end = dsp_hbor_end - bor_right;
239 dsp_vact_st = dsp_vbor_st + bor_up;
240 dsp_vact_end = dsp_vbor_end - bor_down;
244 dst_w = dsp_hact_end - dsp_hact_st ;
245 dst_h = dsp_vact_end - dsp_vact_st ;
247 if(src_w > dst_w) //ÅжÏhorµÄËõ·Åģʽ 0£ºno_scl 1£ºscl_up 2£ºscl_down
249 scl_hor_mode = 0x2; //scl_down
250 if(hor_down_mode == 0)//bilinear
252 if((src_w-1)/(dst_w-1) > 2)
254 scl_h_factor = ((src_w-1)<<14)/(dst_w-1);
257 scl_h_factor = ((src_w-2)<<14)/(dst_w-1);
261 scl_h_factor = ((dst_w)<<16)/(src_w-1);
264 else if(src_w == dst_w)
266 scl_hor_mode = 0x0; //no_Scl
271 scl_hor_mode = 0x1; //scl_up
272 scl_h_factor = ((src_w-1)<<16)/(dst_w-1);
275 if(src_h > dst_h) //ÅжÏverµÄËõ·Åģʽ 0£ºno_scl 1£ºscl_up 2£ºscl_down
277 scl_ver_mode = 0x2; //scl_down
278 if(ver_down_mode == 0)//bilinearhor_down_mode,u8 ver_down_mode
280 if((src_h-1)/(dst_h-1) > 2)
282 scl_v_factor = ((src_h-1)<<14)/(dst_h-1);
285 scl_v_factor = ((src_h-2)<<14)/(dst_h-1);
289 scl_v_factor = ((dst_h)<<16)/(src_h-1);
292 else if(src_h == dst_h)
294 scl_ver_mode = 0x0; //no_Scl
299 scl_ver_mode = 0x1; //scl_up
300 scl_v_factor = ((src_h-1)<<16)/(dst_h-1);
304 scl_reg0_value = (0x1ff<<16) | SCL_EN | (scl_hor_mode<<1) |
305 (scl_ver_mode<<3) | (bic_coe_sel<<5) |
306 (hor_down_mode<<7) | (ver_down_mode<<8) ;
308 scl_reg1_value = (scl_v_factor << 16) | scl_h_factor ;
309 //dsp_frame register2
310 scl_reg2_value = dst_frame_vst<<16 | dst_frame_hst ;
312 scl_reg3_value = dsp_hs_end<<16 | dsp_htotal ;
314 scl_reg4_value = dsp_hact_end <<16 | dsp_hact_st ;
316 scl_reg5_value = dsp_vs_end<<16 | dsp_vtotal ;
318 scl_reg6_value = dsp_vact_end<<16 | dsp_vact_st ;
320 scl_reg7_value = dsp_hbor_end<<16 | dsp_hbor_st ;
322 scl_reg8_value = dsp_vbor_end<<16 | dsp_vbor_st ;
325 rk616->write_dev(rk616,SCL_REG0,&scl_reg0_value);
326 rk616->write_dev(rk616,SCL_REG1,&scl_reg1_value);
327 rk616->write_dev(rk616,SCL_REG2,&scl_reg2_value);
328 rk616->write_dev(rk616,SCL_REG3,&scl_reg3_value);
329 rk616->write_dev(rk616,SCL_REG4,&scl_reg4_value);
330 rk616->write_dev(rk616,SCL_REG5,&scl_reg5_value);
331 rk616->write_dev(rk616,SCL_REG6,&scl_reg6_value);
332 rk616->write_dev(rk616,SCL_REG7,&scl_reg7_value);
333 rk616->write_dev(rk616,SCL_REG8,&scl_reg8_value);
340 static int rk616_dual_input_cfg(struct mfd_rk616 *rk616,rk_screen *screen,
343 struct rk616_platform_data *pdata = rk616->pdata;
344 struct rk616_route *route = &rk616->route;
346 route->vif0_bypass = VIF0_CLK_BYPASS;
348 route->vif0_clk_sel = VIF0_CLKIN_SEL(VIF_CLKIN_SEL_PLL0);
349 route->pll0_clk_sel = PLL0_CLK_SEL(LCD0_DCLK);
350 route->pll1_clk_sel = PLL1_CLK_SEL(MCLK_12M);
351 route->vif1_clk_sel = VIF1_CLKIN_SEL(VIF_CLKIN_SEL_PLL1);
352 route->hdmi_sel = HDMI_IN_SEL(HDMI_CLK_SEL_VIF1);
353 if(enable) //hdmi plug in
355 route->vif1_bypass = 0;
361 route->vif1_bypass = VIF1_CLK_BYPASS;
365 route->sclin_sel = SCL_IN_SEL(SCL_SEL_VIF0); //from vif0
366 route->scl_en = 0; //dual lcdc, scaler not needed
367 route->dither_sel = DITHER_IN_SEL(DITHER_SEL_VIF0); //dither from vif0
368 route->lcd1_input = 1;
371 if(screen->type == SCREEN_RGB)
374 route->lvds_mode = RGB; //rgb output
376 else if(screen->type == SCREEN_LVDS)
379 route->lvds_mode = LVDS;
380 route->lvds_ch_nr = pdata->lvds_ch_nr;
382 else if(screen->type == SCREEN_MIPI)
388 dev_err(rk616->dev,"un supported interface:%d\n",screen->type);
396 static int rk616_lcd0_input_lcd1_unused_cfg(struct mfd_rk616 *rk616,rk_screen *screen,
399 struct rk616_platform_data *pdata = rk616->pdata;
400 struct rk616_route *route = &rk616->route;
402 if(enable) //hdmi plug in
404 route->vif0_bypass = 0;
406 route->vif0_clk_sel = VIF0_CLKIN_SEL(VIF_CLKIN_SEL_PLL0);
407 route->sclin_sel = SCL_IN_SEL(SCL_SEL_VIF0); //from vif0
409 route->sclk_sel = SCLK_SEL(SCLK_SEL_PLL1);
410 route->dither_sel = DITHER_IN_SEL(DITHER_SEL_SCL); //dither from sclaer
411 route->hdmi_sel = HDMI_IN_SEL(HDMI_CLK_SEL_VIF0);//from vif0
416 route->vif0_bypass = VIF0_CLK_BYPASS;
418 route->sclin_sel = SCL_IN_SEL(SCL_SEL_VIF0); //from vif0
420 route->dither_sel = DITHER_IN_SEL(DITHER_SEL_VIF0); //dither from sclaer
421 route->hdmi_sel = HDMI_IN_SEL(HDMI_CLK_SEL_VIF0);//from vif0
423 route->pll1_clk_sel = PLL1_CLK_SEL(LCD0_DCLK);
424 route->pll0_clk_sel = PLL0_CLK_SEL(LCD0_DCLK);
425 route->vif1_bypass = VIF1_CLK_BYPASS;
427 route->lcd1_input = 0;
429 if(screen->type == SCREEN_RGB)
432 route->lvds_mode = RGB; //rgb output
434 else if(screen->type == SCREEN_LVDS)
437 route->lvds_mode = LVDS;
438 route->lvds_ch_nr = pdata->lvds_ch_nr;
440 else if(screen->type == SCREEN_MIPI)
450 static int rk616_lcd0_input_lcd1_output_cfg(struct mfd_rk616 *rk616,rk_screen *screen,
453 struct rk616_route *route = &rk616->route;
457 route->vif0_bypass = 0;
459 route->vif0_clk_sel = VIF0_CLKIN_SEL(VIF_CLKIN_SEL_PLL0);
460 route->sclin_sel = SCL_IN_SEL(SCL_SEL_VIF0); //from vif0
462 route->sclk_sel = SCLK_SEL(SCLK_SEL_PLL1);
463 route->dither_sel = DITHER_IN_SEL(DITHER_SEL_SCL); //dither from sclaer
464 route->hdmi_sel = HDMI_IN_SEL(HDMI_CLK_SEL_VIF0);//from vif0
468 route->vif0_bypass = VIF0_CLK_BYPASS;
470 route->sclin_sel = SCL_IN_SEL(SCL_SEL_VIF0); //from vif0
472 route->dither_sel = DITHER_IN_SEL(DITHER_SEL_VIF0); //dither from sclaer
473 route->hdmi_sel = HDMI_IN_SEL(HDMI_CLK_SEL_VIF0);//from vif0
475 route->pll0_clk_sel = PLL0_CLK_SEL(LCD0_DCLK);
476 route->pll1_clk_sel = PLL1_CLK_SEL(LCD0_DCLK);
477 route->vif1_bypass = VIF1_CLK_BYPASS;
479 route->lcd1_input = 0; //lcd1 as out put
487 static int rk616_lcd0_unused_lcd1_input_cfg(struct mfd_rk616 *rk616,rk_screen *screen,
490 struct rk616_platform_data *pdata = rk616->pdata;
491 struct rk616_route *route = &rk616->route;
493 route->pll0_clk_sel = PLL0_CLK_SEL(LCD1_DCLK);
494 route->pll1_clk_sel = PLL1_CLK_SEL(LCD1_DCLK);
495 route->vif0_bypass = VIF0_CLK_BYPASS;
499 route->vif1_bypass = 0;
501 route->scl_bypass = 0;
505 route->vif1_bypass = VIF1_CLK_BYPASS;
507 route->scl_bypass = 1; //1:1 scaler
509 route->vif1_clk_sel = VIF1_CLKIN_SEL(VIF_CLKIN_SEL_PLL1);
510 route->sclin_sel = SCL_IN_SEL(SCL_SEL_VIF1); //from vif1
512 route->sclk_sel = SCLK_SEL(SCLK_SEL_PLL0);
514 route->dither_sel = DITHER_IN_SEL(DITHER_SEL_SCL); //dither from sclaer
515 route->hdmi_sel = HDMI_IN_SEL(HDMI_CLK_SEL_VIF1); //from vif1
516 route->lcd1_input = 1;
517 if(screen->type == SCREEN_RGB)
520 route->lvds_mode = RGB; //rgb output
522 else if(screen->type == SCREEN_LVDS)
525 route->lvds_mode = LVDS;
526 route->lvds_ch_nr = pdata->lvds_ch_nr;
528 else if(screen->type == SCREEN_MIPI)
534 dev_err(rk616->dev,"un supported interface:%d\n",screen->type);
541 int rk616_set_router(struct mfd_rk616 *rk616,rk_screen *screen,bool enable)
543 struct rk616_platform_data *pdata = rk616->pdata;
546 if((pdata->lcd0_func == INPUT) && (pdata->lcd1_func == INPUT))
549 ret = rk616_dual_input_cfg(rk616,screen,enable);
550 dev_info(rk616->dev,"rk616 use dual input for dual display!\n");
552 else if((pdata->lcd0_func == INPUT) && (pdata->lcd1_func == UNUSED))
554 ret = rk616_lcd0_input_lcd1_unused_cfg(rk616,screen,enable);
557 "rk616 use lcd0 as input and lvds/rgb "
558 "port as output for dual display\n");
560 else if((pdata->lcd0_func == INPUT) && (pdata->lcd1_func == OUTPUT))
562 ret = rk616_lcd0_input_lcd1_output_cfg(rk616,screen,enable);
565 "rk616 use lcd0 as input and lcd1 as "
566 "output for dual display\n");
568 else if((pdata->lcd0_func == UNUSED) && (pdata->lcd1_func == INPUT))
570 ret = rk616_lcd0_unused_lcd1_input_cfg(rk616,screen,enable);
572 "rk616 use lcd1 as input and lvds/rgb as "
573 "output for dual display\n");
578 "invalid configration,please check your"
579 "rk616_platform_data setting in your board file!\n");
590 static int rk616_router_cfg(struct mfd_rk616 *rk616)
594 struct rk616_route *route = &rk616->route;
595 val = (route->pll0_clk_sel) | (route->pll1_clk_sel) |
596 PLL1_CLK_SEL_MASK | PLL0_CLK_SEL_MASK; //pll1 clk from lcdc1_dclk,pll0 clk from lcdc0_dclk,mux_lcdx = lcdx_clk
597 ret = rk616->write_dev(rk616,CRU_CLKSEL0_CON,&val);
599 val = (route->sclk_sel) | SCLK_SEL_MASK;
600 ret = rk616->write_dev(rk616,CRU_CLKSEL1_CON,&val);
602 val = (SCL_IN_SEL_MASK) | (DITHER_IN_SEL_MASK) | (HDMI_IN_SEL_MASK) |
603 (VIF1_CLKIN_SEL_MASK) | (VIF0_CLKIN_SEL_MASK) | (VIF1_CLK_BYPASS << 16) |
604 (VIF0_CLK_BYPASS << 16) |(route->sclin_sel) | (route->dither_sel) |
605 (route->hdmi_sel) | (route->vif1_bypass) | (route->vif0_bypass) |
606 (route->vif1_clk_sel)| (route->vif0_clk_sel);
607 ret = rk616->write_dev(rk616,CRU_CLKSE2_CON,&val);
613 int rk616_display_router_cfg(struct mfd_rk616 *rk616,rk_screen *screen,bool enable)
616 rk_screen *hdmi_screen = screen->ext_screen;
617 ret = rk616_set_router(rk616,screen,enable);
620 ret = rk616_router_cfg(rk616);
621 ret = rk616_vif_cfg(rk616,hdmi_screen,0);
622 ret = rk616_vif_cfg(rk616,hdmi_screen,1);
623 ret = rk616_scaler_cfg(rk616,screen);
630 int rk616_set_vif(struct mfd_rk616 *rk616,rk_screen *screen,bool connect)
632 struct rk616_platform_data *pdata;
635 printk(KERN_ERR "%s:mfd rk616 is null!\n",__func__);
640 pdata = rk616->pdata;
645 rk616_vif_disable(rk616,0);
646 rk616_vif_disable(rk616,1);
649 #if defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF)
652 if((pdata->lcd0_func == INPUT) && (pdata->lcd1_func == INPUT))
655 rk616_dual_input_cfg(rk616,screen,connect);
656 dev_info(rk616->dev,"rk616 use dual input for dual display!\n");
658 else if((pdata->lcd0_func == INPUT) && (pdata->lcd1_func == UNUSED))
660 rk616_lcd0_input_lcd1_unused_cfg(rk616,screen,connect);
661 dev_info(rk616->dev,"rk616 use lcd0 input for hdmi display!\n");
663 rk616_vif_cfg(rk616,screen,0);
664 rk616_vif_cfg(rk616,screen,1);
665 rk616_scaler_disable(rk616);