2 #include <linux/delay.h>
4 #include <mach/iomux.h>
5 #include <mach/board.h>
7 #include <linux/mfd/rk610_core.h>
8 #include <linux/rk_fb.h>
9 #include "../hdmi/rk_hdmi.h"
11 static struct rk610_lcd_info *g_lcd_inf = NULL;
12 //static int rk610_scaler_read_p0_reg(struct i2c_client *client, char reg, char *val)
14 //return i2c_master_reg8_recv(client, reg, val, 1, 100*1000) > 0? 0: -EINVAL;
17 static int rk610_scaler_write_p0_reg(struct i2c_client *client, char reg, char *val)
19 return i2c_master_reg8_send(client, reg, val, 1, 100*1000) > 0? 0: -EINVAL;
21 static void rk610_scaler_pll_enable(struct i2c_client *client)
24 RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
26 g_lcd_inf->scl_inf.pll_pwr = ENABLE;
28 c = S_PLL_PWR(0)|S_PLL_RESET(0)|S_PLL_BYPASS(0);
29 rk610_scaler_write_p0_reg(client, S_PLL_CON2, &c);
31 static void rk610_scaler_pll_disable(struct i2c_client *client)
34 RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
36 g_lcd_inf->scl_inf.pll_pwr = DISABLE;
38 c = S_PLL_PWR(1) |S_PLL_RESET(0) |S_PLL_BYPASS(1);
39 rk610_scaler_write_p0_reg(client, S_PLL_CON2, &c);
41 static void rk610_scaler_enable(struct i2c_client *client)
44 bool den_inv = 0,hv_sync_inv = 0,clk_inv = 0;
45 RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
46 g_lcd_inf->scl_inf.scl_pwr = ENABLE;
47 #if defined(CONFIG_HDMI_DUAL_DISP) || defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF)
48 if(g_lcd_inf->screen !=NULL){
49 den_inv = g_lcd_inf->screen->s_den_inv;
50 hv_sync_inv = g_lcd_inf->screen->s_hv_sync_inv;
51 clk_inv = g_lcd_inf->screen->s_clk_inv;
54 c= SCL_BYPASS(0) |SCL_DEN_INV(den_inv) |SCL_H_V_SYNC_INV(hv_sync_inv) |SCL_OUT_CLK_INV(clk_inv) |SCL_ENABLE(ENABLE);
55 rk610_scaler_write_p0_reg(client, SCL_CON0, &c);
57 static void rk610_scaler_disable(struct i2c_client *client)
60 bool den_inv = 0,hv_sync_inv = 0,clk_inv = 0;
61 RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
63 g_lcd_inf->scl_inf.scl_pwr = DISABLE;
64 #if defined(CONFIG_HDMI_DUAL_DISP) || defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF)
65 if(g_lcd_inf->screen !=NULL){
66 den_inv = g_lcd_inf->screen->s_den_inv;
67 hv_sync_inv = g_lcd_inf->screen->s_hv_sync_inv;
68 clk_inv = g_lcd_inf->screen->s_clk_inv;
71 c= SCL_BYPASS(1) |SCL_DEN_INV(den_inv) |SCL_H_V_SYNC_INV(hv_sync_inv) |SCL_OUT_CLK_INV(clk_inv) |SCL_ENABLE(DISABLE);
72 rk610_scaler_write_p0_reg(client, SCL_CON0, &c);
75 static int rk610_output_config(struct i2c_client *client,struct rk29fb_screen *screen,int mode)
78 RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
79 if(SCREEN_LVDS == screen->type){
80 if(mode == LCD_OUT_SCL || mode == LCD_OUT_BYPASS){
81 c = LVDS_OUT_CLK_PIN(0) |LVDS_OUT_CLK_PWR_PIN(1) |LVDS_PLL_PWR_PIN(0) \
82 |LVDS_LANE_IN_FORMAT(DATA_D0_MSB) \
83 |LVDS_OUTPUT_FORMAT(screen->lvds_format) | LVDS_BIASE_PWR(1);
84 #if defined(CONFIG_DUAL_LCDC_DUAL_DISP_IN_KERNEL) && defined(CONFIG_HDMI_RK610)
85 c |= LVDS_INPUT_SOURCE(FROM_LCD1);
87 c |= LVDS_INPUT_SOURCE(FROM_LCD0_OR_SCL);
89 rk610_scaler_write_p0_reg(client, LVDS_CON0, &c);
90 c = LCD1_OUT_ENABLE(LCD1_AS_IN);
91 rk610_scaler_write_p0_reg(client, LCD1_CON, &c);
92 c = LVDS_OUT_ENABLE(0x0) |LVDS_TX_PWR_ENABLE(0x0);
93 rk610_scaler_write_p0_reg(client, LVDS_CON1, &c);
96 c = LVDS_OUT_CLK_PIN(0) |LVDS_OUT_CLK_PWR_PIN(0) |LVDS_PLL_PWR_PIN(1) \
97 |LVDS_LANE_IN_FORMAT(DATA_D0_MSB) \
98 |LVDS_OUTPUT_FORMAT(screen->lvds_format) | LVDS_BIASE_PWR(0);
99 #if defined(CONFIG_DUAL_LCDC_DUAL_DISP_IN_KERNEL) && defined(CONFIG_HDMI_RK610)
100 c |= LVDS_INPUT_SOURCE(FROM_LCD1);
102 c |= LVDS_INPUT_SOURCE(FROM_LCD0_OR_SCL);
104 c = LCD1_OUT_ENABLE(LCD1_AS_IN);
105 rk610_scaler_write_p0_reg(client, LCD1_CON, &c);
106 rk610_scaler_write_p0_reg(client, LVDS_CON0, &c);
107 c = LVDS_OUT_ENABLE(0xf) |LVDS_TX_PWR_ENABLE(0xf);
108 rk610_scaler_write_p0_reg(client, LVDS_CON1, &c);
111 }else if(SCREEN_RGB == screen->type){
112 if(mode == LCD_OUT_SCL || mode == LCD_OUT_BYPASS){
113 c = LCD1_OUT_ENABLE(LCD1_AS_OUT) | LCD1_OUT_SRC((mode == LCD_OUT_SCL)?LCD1_FROM_SCL : LCD1_FROM_LCD0);
114 rk610_scaler_write_p0_reg(client, LCD1_CON, &c);
117 c = LCD1_OUT_ENABLE(LCD1_AS_IN);
118 rk610_scaler_write_p0_reg(client, LCD1_CON, &c);
123 #if defined(CONFIG_HDMI_DUAL_DISP) || defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF)
124 static int rk610_scaler_pll_set(struct i2c_client *client,struct rk29fb_screen *screen,u32 clkin )
128 RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
129 /***************SET SCALER PLL FROM CLKIN ,DIV 0*/
130 if(screen->s_pixclock != 0){
131 OD = (screen->s_pixclock)&0x3;
132 N = (screen->s_pixclock >>4)&0xf;
133 M = (screen->s_pixclock >>8)&0xff;
135 RK610_ERR(&client->dev,"RK610 Scaler pll not support rate \n");
137 c = S_PLL_FROM_DIV<<3 | S_PLL_DIV(0);
138 rk610_scaler_write_p0_reg(client, CLOCK_CON0, &c);
140 c = S_DIV_N(N)| S_DIV_OD(OD);
141 rk610_scaler_write_p0_reg(client, S_PLL_CON0, &c);
143 rk610_scaler_write_p0_reg(client, S_PLL_CON1, &c);
144 rk610_scaler_pll_enable(client);
149 static int scale_hv_factor(struct i2c_client *client ,u32 Hin_act, u32 Hout_act, u32 Vin_act, u32 Vout_act)
152 u32 hfactor_f,vfactor_f,scl_factor_f;
155 struct scl_hv_info HV2;
156 hfactor_f = ((Hin_act-1)*4096)/(Hout_act-1);
159 else if(hfactor_f>(int)hfactor_f)
160 {hfactor = (int)hfactor_f+1;}
162 {hfactor = (int)hfactor_f;}
164 scl_factor_f = Vin_act/Vout_act;
166 {vfactor_f = ((Vin_act-1)*4096)/(Vout_act-1);}
168 {vfactor_f = ((Vin_act-2)*4096)/(Vout_act-1);}
171 else if(vfactor_f>(int)vfactor_f)
172 {vfactor = (int)vfactor_f+1;}
174 {vfactor = (int)vfactor_f;}
179 c = SCL_H_FACTOR_LSB(HV2.scl_h);
180 rk610_scaler_write_p0_reg(client, SCL_CON1, &c);
181 c = SCL_H_FACTOR_MSB(HV2.scl_h);
182 rk610_scaler_write_p0_reg(client, SCL_CON2, &c);
184 c = SCL_V_FACTOR_LSB(HV2.scl_v);
185 rk610_scaler_write_p0_reg(client, SCL_CON3, &c);
186 c = SCL_V_FACTOR_MSB(HV2.scl_v);
187 rk610_scaler_write_p0_reg(client, SCL_CON4, &c);
191 static int rk610_scaler_fator_config(struct i2c_client *client ,struct rk29fb_screen *screen)
193 switch(screen->hdmi_resolution){
194 case HDMI_1920x1080p_60Hz:
195 case HDMI_1920x1080p_50Hz:
196 rk610_scaler_pll_set(client,screen,148500000);
197 /***************set scaler factor********************/
198 scale_hv_factor(client,1920,screen->x_res,1080,screen->y_res);
200 case HDMI_1280x720p_60Hz:
201 case HDMI_1280x720p_50Hz:
202 rk610_scaler_pll_set(client,screen,74250000);
203 /***************set scaler factor********************/
204 scale_hv_factor(client,1280,screen->x_res,720,screen->y_res);
206 case HDMI_720x576p_50Hz_16_9:
207 case HDMI_720x576p_50Hz_4_3:
208 rk610_scaler_pll_set(client,screen,27000000);
209 /***************set scaler factor********************/
210 scale_hv_factor(client,720,screen->x_res,576,screen->y_res);
212 case HDMI_720x480p_60Hz_16_9:
213 case HDMI_720x480p_60Hz_4_3:
214 rk610_scaler_pll_set(client,screen,27000000);
215 /***************set scaler factor********************/
216 scale_hv_factor(client,720,screen->x_res,480,screen->y_res);
219 RK610_ERR(&client->dev,"RK610 not support dual display at hdmi resolution=%d \n",screen->hdmi_resolution);
225 static int rk610_scaler_output_timing_config(struct i2c_client *client,struct rk29fb_screen *screen)
228 int h_st = screen->s_hsync_st;
229 int hs_end = screen->s_hsync_len;
230 int h_act_st = hs_end + screen->s_left_margin;
231 int xres = screen->x_res;
232 int h_act_end = h_act_st + xres;
233 int h_total = h_act_end + screen->s_right_margin;
234 int v_st = screen->s_vsync_st;
235 int vs_end = screen->s_vsync_len;
236 int v_act_st = vs_end + screen->s_upper_margin;
237 int yres = screen->y_res;
238 int v_act_end = v_act_st + yres;
239 int v_total = v_act_end + screen->s_lower_margin;
241 /* SCL display Frame start point */
242 c = SCL_DSP_HST_LSB(h_st);
243 rk610_scaler_write_p0_reg(client, SCL_CON5, &c);
244 c = SCL_DSP_HST_MSB(h_st);
245 rk610_scaler_write_p0_reg(client, SCL_CON6, &c);
247 c = SCL_DSP_VST_LSB(v_st);
248 rk610_scaler_write_p0_reg(client, SCL_CON7, &c);
249 c = SCL_DSP_VST_MSB(v_st);
250 rk610_scaler_write_p0_reg(client, SCL_CON8, &c);
251 /* SCL output timing */
253 c = SCL_DSP_HTOTAL_LSB(h_total);
254 rk610_scaler_write_p0_reg(client, SCL_CON9, &c);
255 c = SCL_DSP_HTOTAL_MSB(h_total);
256 rk610_scaler_write_p0_reg(client, SCL_CON10, &c);
258 c = SCL_DSP_HS_END(hs_end);
259 rk610_scaler_write_p0_reg(client, SCL_CON11, &c);
261 c = SCL_DSP_HACT_ST_LSB(h_act_st);
262 rk610_scaler_write_p0_reg(client, SCL_CON12, &c);
263 c = SCL_DSP_HACT_ST_MSB(h_act_st);
264 rk610_scaler_write_p0_reg(client, SCL_CON13, &c);
266 c = SCL_DSP_HACT_END_LSB(h_act_end);
267 rk610_scaler_write_p0_reg(client, SCL_CON14, &c);
268 c = SCL_DSP_HACT_END_MSB(h_act_end);
269 rk610_scaler_write_p0_reg(client, SCL_CON15, &c);
271 c = SCL_DSP_VTOTAL_LSB(v_total);
272 rk610_scaler_write_p0_reg(client, SCL_CON16, &c);
273 c = SCL_DSP_VTOTAL_MSB(v_total);
274 rk610_scaler_write_p0_reg(client, SCL_CON17, &c);
276 c = SCL_DSP_VS_END(vs_end);
277 rk610_scaler_write_p0_reg(client, SCL_CON18, &c);
279 c = SCL_DSP_VACT_ST(v_act_st);
280 rk610_scaler_write_p0_reg(client, SCL_CON19, &c);
282 c = SCL_DSP_VACT_END_LSB(v_act_end);
283 rk610_scaler_write_p0_reg(client, SCL_CON20, &c);
284 c = SCL_DSP_VACT_END_MSB(v_act_end);
285 rk610_scaler_write_p0_reg(client, SCL_CON21, &c);
287 c = SCL_H_BORD_ST_LSB(h_act_st);
288 rk610_scaler_write_p0_reg(client, SCL_CON22, &c);
289 c = SCL_H_BORD_ST_MSB(h_act_st);
290 rk610_scaler_write_p0_reg(client, SCL_CON23, &c);
292 c = SCL_H_BORD_END_LSB(h_act_end);
293 rk610_scaler_write_p0_reg(client, SCL_CON24, &c);
294 c = SCL_H_BORD_END_MSB(h_act_end);
295 rk610_scaler_write_p0_reg(client, SCL_CON25, &c);
297 c = SCL_V_BORD_ST(v_act_st);
298 rk610_scaler_write_p0_reg(client, SCL_CON26, &c);
300 c = SCL_V_BORD_END_LSB(v_act_end);
301 rk610_scaler_write_p0_reg(client, SCL_CON27, &c);
302 c = SCL_V_BORD_END_MSB(v_act_end);
303 rk610_scaler_write_p0_reg(client, SCL_CON28, &c);
307 static int rk610_scaler_chg(struct i2c_client *client ,struct rk29fb_screen *screen)
310 RK610_DBG(&client->dev,"%s screen->hdmi_resolution=%d\n",__FUNCTION__,screen->hdmi_resolution);
311 rk610_scaler_fator_config(client,screen);
312 rk610_scaler_enable(client);
313 rk610_scaler_output_timing_config(client,screen);
319 static int rk610_lcd_scaler_bypass(struct i2c_client *client,bool enable)//enable:0 bypass 1: scale
321 RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
323 rk610_scaler_disable(client);
324 rk610_scaler_pll_disable(client);
329 #ifdef CONFIG_HAS_EARLYSUSPEND
330 static void rk610_lcd_early_suspend(struct early_suspend *h)
332 struct i2c_client *client = g_lcd_inf->client;
334 RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
335 if(g_lcd_inf->screen != NULL){
336 rk610_output_config(client,g_lcd_inf->screen,LCD_OUT_DISABLE);
339 if(ENABLE == g_lcd_inf->scl_inf.scl_pwr){
340 c= SCL_BYPASS(1) |SCL_DEN_INV(0) |SCL_H_V_SYNC_INV(0) |SCL_OUT_CLK_INV(0) |SCL_ENABLE(DISABLE);
341 rk610_scaler_write_p0_reg(client, SCL_CON0, &c);
343 if(ENABLE == g_lcd_inf->scl_inf.pll_pwr ){
344 c = S_PLL_PWR(1) |S_PLL_RESET(0) |S_PLL_BYPASS(1);
345 rk610_scaler_write_p0_reg(client, S_PLL_CON2, &c);
349 static void rk610_lcd_early_resume(struct early_suspend *h)
351 struct i2c_client *client = g_lcd_inf->client;
353 RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
355 if(g_lcd_inf->screen != NULL){
356 rk610_output_config(client,g_lcd_inf->screen,g_lcd_inf->disp_mode);
358 if(ENABLE == g_lcd_inf->scl_inf.scl_pwr){
359 c= SCL_BYPASS(0) |SCL_DEN_INV(0) |SCL_H_V_SYNC_INV(0) |SCL_OUT_CLK_INV(0) |SCL_ENABLE(ENABLE);
360 rk610_scaler_write_p0_reg(client, SCL_CON0, &c);
362 if(ENABLE == g_lcd_inf->scl_inf.pll_pwr ){
363 c = S_PLL_PWR(1) |S_PLL_RESET(0) |S_PLL_BYPASS(1);
364 rk610_scaler_write_p0_reg(client, S_PLL_CON2, &c);
368 int rk610_lcd_scaler_set_param(struct rk29fb_screen *screen,bool enable )//enable:0 bypass 1: scale
371 struct i2c_client *client = g_lcd_inf->client;
373 printk("%s client == NULL FAIL\n",__FUNCTION__);
377 printk("%s screen == NULL FAIL\n",__FUNCTION__);
380 RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
382 g_lcd_inf->screen = screen;
384 #if defined(CONFIG_HDMI_DUAL_DISP) || defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF)
386 g_lcd_inf->disp_mode = LCD_OUT_SCL;
387 rk610_output_config(client,screen,LCD_OUT_SCL);
388 ret = rk610_scaler_chg(client,screen);
393 g_lcd_inf->disp_mode = LCD_OUT_BYPASS;
394 rk610_output_config(client,screen,LCD_OUT_BYPASS);
395 ret = rk610_lcd_scaler_bypass(client,enable);
399 int rk610_lcd_init(struct rk610_core_info *rk610_core_info)
401 if(rk610_core_info->client == NULL){
402 printk("%s client == NULL FAIL\n",__FUNCTION__);
405 RK610_DBG(&rk610_core_info->client->dev,"%s \n",__FUNCTION__);
407 g_lcd_inf = kmalloc(sizeof(struct rk610_lcd_info), GFP_KERNEL);
410 dev_err(&rk610_core_info->client->dev, ">> rk610 inf kmalloc fail!");
413 memset(g_lcd_inf, 0, sizeof(struct rk610_lcd_info));
415 g_lcd_inf->client= rk610_core_info->client;
417 rk610_core_info->lcd_pdata = (void *)g_lcd_inf;
418 #ifdef CONFIG_HAS_EARLYSUSPEND
419 g_lcd_inf->early_suspend.suspend = rk610_lcd_early_suspend;
420 g_lcd_inf->early_suspend.resume = rk610_lcd_early_resume;
421 g_lcd_inf->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB- 1;
422 register_early_suspend(&g_lcd_inf->early_suspend);
424 g_lcd_inf->scl_inf.pll_pwr = DISABLE;
425 g_lcd_inf->scl_inf.scl_pwr = DISABLE;
426 g_lcd_inf->disp_mode = LCD_OUT_BYPASS;
430 static int rk610_lcd_probe(struct platform_device *pdev)
432 struct rk610_core_info *core_info = NULL;
433 rk_screen *screen = NULL;
435 core_info = dev_get_drvdata(pdev->dev.parent);
438 dev_err(&pdev->dev,"rk610 core info is null\n");
441 screen = rk_fb_get_prmry_screen();
444 dev_err(&pdev->dev,"the fb prmry screen is null!\n");
448 #if defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF)
449 screen->sscreen_set = rk610_lcd_scaler_set_param;
451 rk610_lcd_init(core_info);
452 rk610_lcd_scaler_set_param(screen,0);
457 static int rk610_lcd_remove(struct platform_device *pdev)
463 static void rk610_lcd_shutdown(struct platform_device *pdev)
469 static struct platform_driver rk610_lcd_driver = {
472 .owner = THIS_MODULE,
474 .probe = rk610_lcd_probe,
475 .remove = rk610_lcd_remove,
476 .shutdown = rk610_lcd_shutdown,
479 static int __init rk610_lcd_module_init(void)
481 return platform_driver_register(&rk610_lcd_driver);
483 fs_initcall(rk610_lcd_module_init);
484 static void __exit rk610_lcd_exit(void)
486 platform_driver_unregister(&rk610_lcd_driver);
488 module_exit(rk610_lcd_exit);