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);
115 dev_info(rk616->dev,"rk616 vif%d enable\n",id);
122 static int rk616_vif_disable(struct mfd_rk616 *rk616,int id)
127 printk(KERN_INFO "rk616 vif%d disable\n",id);
129 if(id == 0) //video interface 0
132 val = (VIF0_EN << 16); //disable vif0
133 ret = rk616->write_dev(rk616,VIF0_REG0,&val);
134 clk_set_rate(rk616->mclk, 11289600);
138 else //vide0 interface 1
141 val = (VIF0_EN << 16); //disabl VIF1
142 ret = rk616->write_dev(rk616,VIF1_REG0,&val);
143 clk_set_rate(rk616->mclk, 11289600);
150 static int rk616_scaler_disable(struct mfd_rk616 *rk616)
154 val &= (~SCL_EN); //disable scaler
156 ret = rk616->write_dev(rk616,SCL_REG0,&val);
159 int rk616_scaler_cfg(struct mfd_rk616 *rk616,rk_screen *screen)
163 u32 scl_hor_mode,scl_ver_mode;
164 u32 scl_v_factor,scl_h_factor;
165 u32 scl_reg0_value,scl_reg1_value,scl_reg2_value; //scl_con,scl_h_factor,scl_v_factor,
166 u32 scl_reg3_value,scl_reg4_value,scl_reg5_value,scl_reg6_value; //dsp_frame_hst,dsp_frame_vst,dsp_timing,dsp_act_timing
167 u32 scl_reg7_value,scl_reg8_value; //dsp_hbor ,dsp_vbor
168 u32 dst_frame_hst,dst_frame_vst; //ʱÐò»º´æ
169 u32 dst_htotal,dst_hs_end,dst_hact_st,dst_hact_end; //ÆÁÄ»typical h²ÎÊý
170 u32 dst_vtotal,dst_vs_end,dst_vact_st,dst_vact_end; //ÆÁÄ»typical v²ÎÊý
172 u32 dsp_htotal,dsp_hs_end,dsp_hact_st,dsp_hact_end; //scalerÊä³öµÄtiming²ÎÊý
173 u32 dsp_vtotal,dsp_vs_end,dsp_vact_st,dsp_vact_end;
174 u32 dsp_hbor_end,dsp_hbor_st,dsp_vbor_end,dsp_vbor_st;
175 u32 src_w,src_h,src_htotal,src_vtotal,dst_w,dst_h,src_hact_st,src_vact_st;
180 u8 hor_down_mode = 0; //1:average,0:bilinear
181 u8 ver_down_mode = 0;
187 struct rk616_route *route = &rk616->route;
192 rk616_scaler_disable(rk616);
200 dev_err(rk616->dev,"%s:screen is null!\n",__func__);
204 if(route->scl_bypass)
207 dst->pll_cfg_val = 0x01422014;
211 src = screen->ext_screen;
213 if(route->sclk_sel == SCLK_SEL(SCLK_SEL_PLL0))
217 rk616_pll_set_rate(rk616,pll_id,dst->pll_cfg_val,dst->frac);
218 dst_frame_vst = dst->scl_vst;
219 dst_frame_hst = dst->scl_hst;
224 src_htotal = src->hsync_len + src->left_margin + src->x_res + src->right_margin;
225 src_vact_st = src->vsync_len + src->upper_margin ;
226 dst_vact_st = dst->vsync_len + dst->upper_margin;
228 dsp_htotal = dst->hsync_len + dst->left_margin + dst->x_res + dst->right_margin; //dst_htotal ;
229 dsp_hs_end = dst->hsync_len;
231 dsp_vtotal = dst->vsync_len + dst->upper_margin + dst->y_res + dst->lower_margin;
232 dsp_vs_end = dst->vsync_len;
234 dsp_hbor_end = dst->hsync_len + dst->left_margin + dst->x_res;
235 dsp_hbor_st = dst->hsync_len + dst->left_margin ;
236 dsp_vbor_end = dst->vsync_len + dst->upper_margin + dst->y_res; //dst_vact_end ;
237 dsp_vbor_st = dst_vact_st ;
239 dsp_hact_st = dsp_hbor_st + bor_left;
240 dsp_hact_end = dsp_hbor_end - bor_right;
241 dsp_vact_st = dsp_vbor_st + bor_up;
242 dsp_vact_end = dsp_vbor_end - bor_down;
246 dst_w = dsp_hact_end - dsp_hact_st ;
247 dst_h = dsp_vact_end - dsp_vact_st ;
249 if(src_w > dst_w) //ÅжÏhorµÄËõ·Åģʽ 0£ºno_scl 1£ºscl_up 2£ºscl_down
251 scl_hor_mode = 0x2; //scl_down
252 if(hor_down_mode == 0)//bilinear
254 if((src_w-1)/(dst_w-1) > 2)
256 scl_h_factor = ((src_w-1)<<14)/(dst_w-1);
259 scl_h_factor = ((src_w-2)<<14)/(dst_w-1);
263 scl_h_factor = ((dst_w)<<16)/(src_w-1);
266 else if(src_w == dst_w)
268 scl_hor_mode = 0x0; //no_Scl
273 scl_hor_mode = 0x1; //scl_up
274 scl_h_factor = ((src_w-1)<<16)/(dst_w-1);
277 if(src_h > dst_h) //ÅжÏverµÄËõ·Åģʽ 0£ºno_scl 1£ºscl_up 2£ºscl_down
279 scl_ver_mode = 0x2; //scl_down
280 if(ver_down_mode == 0)//bilinearhor_down_mode,u8 ver_down_mode
282 if((src_h-1)/(dst_h-1) > 2)
284 scl_v_factor = ((src_h-1)<<14)/(dst_h-1);
287 scl_v_factor = ((src_h-2)<<14)/(dst_h-1);
291 scl_v_factor = ((dst_h)<<16)/(src_h-1);
294 else if(src_h == dst_h)
296 scl_ver_mode = 0x0; //no_Scl
301 scl_ver_mode = 0x1; //scl_up
302 scl_v_factor = ((src_h-1)<<16)/(dst_h-1);
306 scl_reg0_value = (0x1ff<<16) | SCL_EN | (scl_hor_mode<<1) |
307 (scl_ver_mode<<3) | (bic_coe_sel<<5) |
308 (hor_down_mode<<7) | (ver_down_mode<<8) ;
310 scl_reg1_value = (scl_v_factor << 16) | scl_h_factor ;
311 //dsp_frame register2
312 scl_reg2_value = dst_frame_vst<<16 | dst_frame_hst ;
314 scl_reg3_value = dsp_hs_end<<16 | dsp_htotal ;
316 scl_reg4_value = dsp_hact_end <<16 | dsp_hact_st ;
318 scl_reg5_value = dsp_vs_end<<16 | dsp_vtotal ;
320 scl_reg6_value = dsp_vact_end<<16 | dsp_vact_st ;
322 scl_reg7_value = dsp_hbor_end<<16 | dsp_hbor_st ;
324 scl_reg8_value = dsp_vbor_end<<16 | dsp_vbor_st ;
327 rk616->write_dev(rk616,SCL_REG0,&scl_reg0_value);
328 rk616->write_dev(rk616,SCL_REG1,&scl_reg1_value);
329 rk616->write_dev(rk616,SCL_REG2,&scl_reg2_value);
330 rk616->write_dev(rk616,SCL_REG3,&scl_reg3_value);
331 rk616->write_dev(rk616,SCL_REG4,&scl_reg4_value);
332 rk616->write_dev(rk616,SCL_REG5,&scl_reg5_value);
333 rk616->write_dev(rk616,SCL_REG6,&scl_reg6_value);
334 rk616->write_dev(rk616,SCL_REG7,&scl_reg7_value);
335 rk616->write_dev(rk616,SCL_REG8,&scl_reg8_value);
342 static int rk616_dual_input_cfg(struct mfd_rk616 *rk616,rk_screen *screen,
345 struct rk616_platform_data *pdata = rk616->pdata;
346 struct rk616_route *route = &rk616->route;
348 route->vif0_bypass = VIF0_CLK_BYPASS;
350 route->vif0_clk_sel = VIF0_CLKIN_SEL(VIF_CLKIN_SEL_PLL0);
351 route->pll0_clk_sel = PLL0_CLK_SEL(LCD0_DCLK);
352 route->pll1_clk_sel = PLL1_CLK_SEL(MCLK_12M);
353 route->vif1_clk_sel = VIF1_CLKIN_SEL(VIF_CLKIN_SEL_PLL1);
354 route->hdmi_sel = HDMI_IN_SEL(HDMI_CLK_SEL_VIF1);
355 if(enable) //hdmi plug in
357 route->vif1_bypass = 0;
363 route->vif1_bypass = VIF1_CLK_BYPASS;
367 route->sclin_sel = SCL_IN_SEL(SCL_SEL_VIF0); //from vif0
368 route->scl_en = 0; //dual lcdc, scaler not needed
369 route->dither_sel = DITHER_IN_SEL(DITHER_SEL_VIF0); //dither from vif0
370 route->lcd1_input = 1;
373 if(screen->type == SCREEN_RGB)
376 route->lvds_mode = RGB; //rgb output
378 else if(screen->type == SCREEN_LVDS)
381 route->lvds_mode = LVDS;
382 route->lvds_ch_nr = pdata->lvds_ch_nr;
384 else if(screen->type == SCREEN_MIPI)
390 dev_err(rk616->dev,"un supported interface:%d\n",screen->type);
398 static int rk616_lcd0_input_lcd1_unused_cfg(struct mfd_rk616 *rk616,rk_screen *screen,
401 struct rk616_platform_data *pdata = rk616->pdata;
402 struct rk616_route *route = &rk616->route;
404 if(enable) //hdmi plug in
406 route->vif0_bypass = 0;
408 route->vif0_clk_sel = VIF0_CLKIN_SEL(VIF_CLKIN_SEL_PLL0);
409 route->sclin_sel = SCL_IN_SEL(SCL_SEL_VIF0); //from vif0
411 route->sclk_sel = SCLK_SEL(SCLK_SEL_PLL1);
412 route->dither_sel = DITHER_IN_SEL(DITHER_SEL_SCL); //dither from sclaer
413 route->hdmi_sel = HDMI_IN_SEL(HDMI_CLK_SEL_VIF0);//from vif0
418 route->vif0_bypass = VIF0_CLK_BYPASS;
420 route->sclin_sel = SCL_IN_SEL(SCL_SEL_VIF0); //from vif0
422 route->dither_sel = DITHER_IN_SEL(DITHER_SEL_VIF0); //dither from sclaer
423 route->hdmi_sel = HDMI_IN_SEL(HDMI_CLK_SEL_VIF0);//from vif0
425 route->pll1_clk_sel = PLL1_CLK_SEL(LCD0_DCLK);
426 route->pll0_clk_sel = PLL0_CLK_SEL(LCD0_DCLK);
427 route->vif1_bypass = VIF1_CLK_BYPASS;
429 route->lcd1_input = 0;
431 if(screen->type == SCREEN_RGB)
434 route->lvds_mode = RGB; //rgb output
436 else if(screen->type == SCREEN_LVDS)
439 route->lvds_mode = LVDS;
440 route->lvds_ch_nr = pdata->lvds_ch_nr;
442 else if(screen->type == SCREEN_MIPI)
452 static int rk616_lcd0_input_lcd1_output_cfg(struct mfd_rk616 *rk616,rk_screen *screen,
455 struct rk616_route *route = &rk616->route;
459 route->vif0_bypass = 0;
461 route->vif0_clk_sel = VIF0_CLKIN_SEL(VIF_CLKIN_SEL_PLL0);
462 route->sclin_sel = SCL_IN_SEL(SCL_SEL_VIF0); //from vif0
464 route->sclk_sel = SCLK_SEL(SCLK_SEL_PLL1);
465 route->dither_sel = DITHER_IN_SEL(DITHER_SEL_SCL); //dither from sclaer
466 route->hdmi_sel = HDMI_IN_SEL(HDMI_CLK_SEL_VIF0);//from vif0
470 route->vif0_bypass = VIF0_CLK_BYPASS;
472 route->sclin_sel = SCL_IN_SEL(SCL_SEL_VIF0); //from vif0
474 route->dither_sel = DITHER_IN_SEL(DITHER_SEL_VIF0); //dither from sclaer
475 route->hdmi_sel = HDMI_IN_SEL(HDMI_CLK_SEL_VIF0);//from vif0
477 route->pll0_clk_sel = PLL0_CLK_SEL(LCD0_DCLK);
478 route->pll1_clk_sel = PLL1_CLK_SEL(LCD0_DCLK);
479 route->vif1_bypass = VIF1_CLK_BYPASS;
481 route->lcd1_input = 0; //lcd1 as out put
489 static int rk616_lcd0_unused_lcd1_input_cfg(struct mfd_rk616 *rk616,rk_screen *screen,
492 struct rk616_platform_data *pdata = rk616->pdata;
493 struct rk616_route *route = &rk616->route;
495 route->pll0_clk_sel = PLL0_CLK_SEL(LCD1_DCLK);
496 route->pll1_clk_sel = PLL1_CLK_SEL(LCD1_DCLK);
497 route->vif0_bypass = VIF0_CLK_BYPASS;
501 route->vif1_bypass = 0;
503 route->scl_bypass = 0;
507 route->vif1_bypass = VIF1_CLK_BYPASS;
509 route->scl_bypass = 1; //1:1 scaler
511 route->vif1_clk_sel = VIF1_CLKIN_SEL(VIF_CLKIN_SEL_PLL1);
512 route->sclin_sel = SCL_IN_SEL(SCL_SEL_VIF1); //from vif1
514 route->sclk_sel = SCLK_SEL(SCLK_SEL_PLL0);
516 route->dither_sel = DITHER_IN_SEL(DITHER_SEL_SCL); //dither from sclaer
517 route->hdmi_sel = HDMI_IN_SEL(HDMI_CLK_SEL_VIF1); //from vif1
518 route->lcd1_input = 1;
519 if(screen->type == SCREEN_RGB)
522 route->lvds_mode = RGB; //rgb output
524 else if(screen->type == SCREEN_LVDS)
527 route->lvds_mode = LVDS;
528 route->lvds_ch_nr = pdata->lvds_ch_nr;
530 else if(screen->type == SCREEN_MIPI)
536 dev_err(rk616->dev,"un supported interface:%d\n",screen->type);
543 int rk616_set_router(struct mfd_rk616 *rk616,rk_screen *screen,bool enable)
545 struct rk616_platform_data *pdata = rk616->pdata;
548 if((pdata->lcd0_func == INPUT) && (pdata->lcd1_func == INPUT))
551 ret = rk616_dual_input_cfg(rk616,screen,enable);
552 dev_info(rk616->dev,"rk616 use dual input for dual display!\n");
554 else if((pdata->lcd0_func == INPUT) && (pdata->lcd1_func == UNUSED))
556 ret = rk616_lcd0_input_lcd1_unused_cfg(rk616,screen,enable);
559 "rk616 use lcd0 as input and lvds/rgb "
560 "port as output for dual display\n");
562 else if((pdata->lcd0_func == INPUT) && (pdata->lcd1_func == OUTPUT))
564 ret = rk616_lcd0_input_lcd1_output_cfg(rk616,screen,enable);
567 "rk616 use lcd0 as input and lcd1 as "
568 "output for dual display\n");
570 else if((pdata->lcd0_func == UNUSED) && (pdata->lcd1_func == INPUT))
572 ret = rk616_lcd0_unused_lcd1_input_cfg(rk616,screen,enable);
574 "rk616 use lcd1 as input and lvds/rgb as "
575 "output for dual display\n");
580 "invalid configration,please check your"
581 "rk616_platform_data setting in your board file!\n");
592 static int rk616_router_cfg(struct mfd_rk616 *rk616)
596 struct rk616_route *route = &rk616->route;
597 val = (route->pll0_clk_sel) | (route->pll1_clk_sel) |
598 PLL1_CLK_SEL_MASK | PLL0_CLK_SEL_MASK; //pll1 clk from lcdc1_dclk,pll0 clk from lcdc0_dclk,mux_lcdx = lcdx_clk
599 ret = rk616->write_dev(rk616,CRU_CLKSEL0_CON,&val);
601 val = (route->sclk_sel) | SCLK_SEL_MASK;
602 ret = rk616->write_dev(rk616,CRU_CLKSEL1_CON,&val);
604 val = (SCL_IN_SEL_MASK) | (DITHER_IN_SEL_MASK) | (HDMI_IN_SEL_MASK) |
605 (VIF1_CLKIN_SEL_MASK) | (VIF0_CLKIN_SEL_MASK) | (VIF1_CLK_BYPASS << 16) |
606 (VIF0_CLK_BYPASS << 16) |(route->sclin_sel) | (route->dither_sel) |
607 (route->hdmi_sel) | (route->vif1_bypass) | (route->vif0_bypass) |
608 (route->vif1_clk_sel)| (route->vif0_clk_sel);
609 ret = rk616->write_dev(rk616,CRU_CLKSE2_CON,&val);
615 int rk616_display_router_cfg(struct mfd_rk616 *rk616,rk_screen *screen,bool enable)
618 rk_screen *hdmi_screen = screen->ext_screen;
619 ret = rk616_set_router(rk616,screen,enable);
622 ret = rk616_router_cfg(rk616);
623 ret = rk616_vif_cfg(rk616,hdmi_screen,0);
624 ret = rk616_vif_cfg(rk616,hdmi_screen,1);
625 ret = rk616_scaler_cfg(rk616,screen);
632 int rk616_set_vif(struct mfd_rk616 *rk616,rk_screen *screen,bool connect)
634 struct rk616_platform_data *pdata;
637 printk(KERN_ERR "%s:mfd rk616 is null!\n",__func__);
642 pdata = rk616->pdata;
647 rk616_vif_disable(rk616,0);
648 rk616_vif_disable(rk616,1);
651 #if defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF)
654 if((pdata->lcd0_func == INPUT) && (pdata->lcd1_func == INPUT))
657 rk616_dual_input_cfg(rk616,screen,connect);
658 dev_info(rk616->dev,"rk616 use dual input for dual display!\n");
660 else if((pdata->lcd0_func == INPUT) && (pdata->lcd1_func == UNUSED))
662 rk616_lcd0_input_lcd1_unused_cfg(rk616,screen,connect);
663 dev_info(rk616->dev,"rk616 use lcd0 input for hdmi display!\n");
665 rk616_router_cfg(rk616);
666 rk616_vif_cfg(rk616,screen,0);
667 rk616_vif_cfg(rk616,screen,1);
668 rk616_scaler_disable(rk616);