rk610 : support dual lcdc display
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / transmitter / rk610_lcd.c
1 #include <linux/fb.h>
2 #include <linux/delay.h>
3 #include <mach/gpio.h>
4 #include <mach/iomux.h>
5 #include <mach/board.h>
6 #include "rk610_lcd.h"
7 #include <linux/mfd/rk610_core.h>
8 #include <linux/rk_fb.h>
9 #include "../hdmi/rk_hdmi.h"
10
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)
13 //{
14         //return i2c_master_reg8_recv(client, reg, val, 1, 100*1000) > 0? 0: -EINVAL;
15 //}
16
17 static int rk610_scaler_write_p0_reg(struct i2c_client *client, char reg, char *val)
18 {
19         return i2c_master_reg8_send(client, reg, val, 1, 100*1000) > 0? 0: -EINVAL;
20 }
21 static void rk610_scaler_pll_enable(struct i2c_client *client)
22 {
23     char c;
24     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
25
26     g_lcd_inf->scl_inf.pll_pwr = ENABLE;
27     
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);
30 }
31 static void rk610_scaler_pll_disable(struct i2c_client *client)
32 {
33     char c;
34     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
35     
36     g_lcd_inf->scl_inf.pll_pwr = DISABLE;
37
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);
40 }
41 static void rk610_scaler_enable(struct i2c_client *client)
42 {
43     char c;
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;
52     }
53     #endif
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);
56 }
57 static void rk610_scaler_disable(struct i2c_client *client)
58 {
59     char c;
60     bool den_inv = 0,hv_sync_inv = 0,clk_inv = 0;
61     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
62     
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;
69     }
70     #endif
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);
73 }
74
75 static int rk610_output_config(struct i2c_client *client,struct rk29fb_screen *screen,int mode)
76 {
77     char c=0;
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)
85                         c |=  LVDS_INPUT_SOURCE(FROM_LCD1);
86                         #else
87                         c |=  LVDS_INPUT_SOURCE(FROM_LCD0_OR_SCL);
88                         #endif                
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);
94             }
95             else{
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) |LVDS_INPUT_SOURCE(FROM_LCD0_OR_SCL) \
98                 |LVDS_OUTPUT_FORMAT(screen->lvds_format) | LVDS_BIASE_PWR(0); 
99                 rk610_scaler_write_p0_reg(client, LVDS_CON0, &c);
100             c = LVDS_OUT_ENABLE(0xf) |LVDS_TX_PWR_ENABLE(0xf); 
101                 rk610_scaler_write_p0_reg(client, LVDS_CON1, &c);
102              
103             }
104         }else if(SCREEN_RGB == screen->type){
105             if(mode == LCD_OUT_SCL || mode == LCD_OUT_BYPASS){
106             c = LCD1_OUT_ENABLE(LCD1_AS_OUT) | LCD1_OUT_SRC((mode == LCD_OUT_SCL)?LCD1_FROM_SCL : LCD1_FROM_LCD0);
107                 rk610_scaler_write_p0_reg(client, LCD1_CON, &c);
108             }
109             else {
110             c = LCD1_OUT_ENABLE(LCD1_AS_IN);
111                 rk610_scaler_write_p0_reg(client, LCD1_CON, &c);
112             }
113         }
114         return 0;
115 }
116 #if defined(CONFIG_HDMI_DUAL_DISP) || defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF)
117 static int rk610_scaler_pll_set(struct i2c_client *client,struct rk29fb_screen *screen,u32 clkin )
118 {
119     char c=0;
120     char M=0,N=0,OD=0;
121     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
122         /***************SET SCALER PLL FROM CLKIN ,DIV 0*/
123     if(screen->s_pixclock != 0){
124         OD = (screen->s_pixclock)&0x3;
125         N = (screen->s_pixclock >>4)&0xf;
126         M = (screen->s_pixclock >>8)&0xff;
127     }else {
128         RK610_ERR(&client->dev,"RK610 Scaler pll not support rate \n");
129     }
130     c = S_PLL_FROM_DIV<<3 | S_PLL_DIV(0);
131         rk610_scaler_write_p0_reg(client, CLOCK_CON0, &c);
132     
133     c = S_DIV_N(N)| S_DIV_OD(OD);
134         rk610_scaler_write_p0_reg(client, S_PLL_CON0, &c);
135     c = S_DIV_M(M);
136     rk610_scaler_write_p0_reg(client, S_PLL_CON1, &c);
137     rk610_scaler_pll_enable(client);
138         return 0;
139 }
140
141
142 static int  scale_hv_factor(struct i2c_client *client ,u32 Hin_act, u32 Hout_act, u32 Vin_act, u32 Vout_act)
143    {
144     char c;
145         u32 hfactor_f,vfactor_f,scl_factor_f;
146         int  hfactor;
147         int  vfactor;
148         struct scl_hv_info  HV2;
149         hfactor_f = ((Hin_act-1)*4096)/(Hout_act-1);
150     if(hfactor_f==4096)
151             {hfactor = 0x1000;}
152         else if(hfactor_f>(int)hfactor_f)
153                 {hfactor = (int)hfactor_f+1;}
154         else
155                 {hfactor = (int)hfactor_f;}
156           
157         scl_factor_f = Vin_act/Vout_act;
158         if(scl_factor_f<2)
159             {vfactor_f = ((Vin_act-1)*4096)/(Vout_act-1);}
160         else
161                 {vfactor_f = ((Vin_act-2)*4096)/(Vout_act-1);} 
162         if(vfactor_f==4096)
163             {vfactor = 0x1000;}
164         else if(vfactor_f>(int)vfactor_f)
165                 {vfactor = (int)vfactor_f+1;}
166         else
167                 {vfactor = (int)vfactor_f;}
168           
169     HV2.scl_h= hfactor;
170     HV2.scl_v= vfactor; 
171            /*       SCL FACTOR          */
172     c = SCL_H_FACTOR_LSB(HV2.scl_h);
173         rk610_scaler_write_p0_reg(client, SCL_CON1, &c);
174     c = SCL_H_FACTOR_MSB(HV2.scl_h);
175         rk610_scaler_write_p0_reg(client, SCL_CON2, &c);
176
177     c = SCL_V_FACTOR_LSB(HV2.scl_v);
178         rk610_scaler_write_p0_reg(client, SCL_CON3, &c);
179     c = SCL_V_FACTOR_MSB(HV2.scl_v);
180         rk610_scaler_write_p0_reg(client, SCL_CON4, &c);
181         return 0;
182    }
183
184 static int rk610_scaler_fator_config(struct i2c_client *client ,struct rk29fb_screen *screen)
185 {
186     switch(screen->hdmi_resolution){
187         case HDMI_1920x1080p_60Hz:
188         case HDMI_1920x1080p_50Hz:
189             rk610_scaler_pll_set(client,screen,148500000);
190             /***************set scaler factor********************/
191             scale_hv_factor(client,1920,screen->x_res,1080,screen->y_res);
192             break;
193         case HDMI_1280x720p_60Hz:
194         case HDMI_1280x720p_50Hz:
195             rk610_scaler_pll_set(client,screen,74250000);
196             /***************set scaler factor********************/
197             scale_hv_factor(client,1280,screen->x_res,720,screen->y_res);
198         break;
199         case HDMI_720x576p_50Hz_16_9:
200         case HDMI_720x576p_50Hz_4_3:
201             rk610_scaler_pll_set(client,screen,27000000);
202             /***************set scaler factor********************/
203             scale_hv_factor(client,720,screen->x_res,576,screen->y_res);
204             break;
205         case HDMI_720x480p_60Hz_16_9:
206         case HDMI_720x480p_60Hz_4_3:
207             rk610_scaler_pll_set(client,screen,27000000);
208             /***************set scaler factor********************/
209             scale_hv_factor(client,720,screen->x_res,480,screen->y_res);
210         break;
211     default :
212         RK610_ERR(&client->dev,"RK610 not support dual display at hdmi resolution=%d \n",screen->hdmi_resolution); 
213         return -1;
214         break;
215     }
216     return 0;
217 }
218 static int rk610_scaler_output_timing_config(struct i2c_client *client,struct rk29fb_screen *screen)
219 {
220     char c;
221     int h_st = screen->s_hsync_st;
222     int hs_end = screen->s_hsync_len;
223     int h_act_st = hs_end + screen->s_left_margin;
224     int xres = screen->x_res;
225     int h_act_end = h_act_st + xres;
226     int h_total = h_act_end + screen->s_right_margin;
227     int v_st = screen->s_vsync_st;
228     int vs_end = screen->s_vsync_len;
229     int v_act_st = vs_end + screen->s_upper_margin;
230     int yres = screen->y_res;    
231     int v_act_end = v_act_st + yres;
232     int v_total = v_act_end + screen->s_lower_margin;
233
234     /*      SCL display Frame start point   */
235     c = SCL_DSP_HST_LSB(h_st);
236         rk610_scaler_write_p0_reg(client, SCL_CON5, &c);
237     c = SCL_DSP_HST_MSB(h_st);
238         rk610_scaler_write_p0_reg(client, SCL_CON6, &c);
239
240     c = SCL_DSP_VST_LSB(v_st);
241         rk610_scaler_write_p0_reg(client, SCL_CON7, &c);
242     c = SCL_DSP_VST_MSB(v_st);
243         rk610_scaler_write_p0_reg(client, SCL_CON8, &c);
244     /*      SCL output timing       */
245
246     c = SCL_DSP_HTOTAL_LSB(h_total);
247         rk610_scaler_write_p0_reg(client, SCL_CON9, &c);
248     c = SCL_DSP_HTOTAL_MSB(h_total);
249         rk610_scaler_write_p0_reg(client, SCL_CON10, &c);
250
251     c = SCL_DSP_HS_END(hs_end);
252         rk610_scaler_write_p0_reg(client, SCL_CON11, &c);
253
254     c = SCL_DSP_HACT_ST_LSB(h_act_st);
255         rk610_scaler_write_p0_reg(client, SCL_CON12, &c);
256     c = SCL_DSP_HACT_ST_MSB(h_act_st);
257         rk610_scaler_write_p0_reg(client, SCL_CON13, &c);
258
259     c = SCL_DSP_HACT_END_LSB(h_act_end);
260         rk610_scaler_write_p0_reg(client, SCL_CON14, &c);
261     c = SCL_DSP_HACT_END_MSB(h_act_end);
262         rk610_scaler_write_p0_reg(client, SCL_CON15, &c);
263
264     c = SCL_DSP_VTOTAL_LSB(v_total);
265         rk610_scaler_write_p0_reg(client, SCL_CON16, &c);
266     c = SCL_DSP_VTOTAL_MSB(v_total);
267         rk610_scaler_write_p0_reg(client, SCL_CON17, &c);
268
269     c = SCL_DSP_VS_END(vs_end);
270         rk610_scaler_write_p0_reg(client, SCL_CON18, &c);
271
272     c = SCL_DSP_VACT_ST(v_act_st);
273         rk610_scaler_write_p0_reg(client, SCL_CON19, &c);
274
275     c = SCL_DSP_VACT_END_LSB(v_act_end);
276         rk610_scaler_write_p0_reg(client, SCL_CON20, &c);
277     c = SCL_DSP_VACT_END_MSB(v_act_end); 
278         rk610_scaler_write_p0_reg(client, SCL_CON21, &c);
279  
280     c = SCL_H_BORD_ST_LSB(h_act_st);
281         rk610_scaler_write_p0_reg(client, SCL_CON22, &c);
282     c = SCL_H_BORD_ST_MSB(h_act_st);
283         rk610_scaler_write_p0_reg(client, SCL_CON23, &c);
284
285     c = SCL_H_BORD_END_LSB(h_act_end);
286         rk610_scaler_write_p0_reg(client, SCL_CON24, &c);
287     c = SCL_H_BORD_END_MSB(h_act_end);
288         rk610_scaler_write_p0_reg(client, SCL_CON25, &c);
289
290     c = SCL_V_BORD_ST(v_act_st);
291         rk610_scaler_write_p0_reg(client, SCL_CON26, &c);
292
293     c = SCL_V_BORD_END_LSB(v_act_end);
294         rk610_scaler_write_p0_reg(client, SCL_CON27, &c);
295     c = SCL_V_BORD_END_MSB(v_act_end);
296         rk610_scaler_write_p0_reg(client, SCL_CON28, &c);
297         
298         return 0;
299 }
300 static int rk610_scaler_chg(struct i2c_client *client ,struct rk29fb_screen *screen)
301 {
302
303     RK610_DBG(&client->dev,"%s screen->hdmi_resolution=%d\n",__FUNCTION__,screen->hdmi_resolution);
304     rk610_scaler_fator_config(client,screen);
305     rk610_scaler_enable(client);
306     rk610_scaler_output_timing_config(client,screen); 
307     
308     return 0;
309
310 }
311 #endif
312 static int rk610_lcd_scaler_bypass(struct i2c_client *client,bool enable)//enable:0 bypass 1: scale
313 {
314     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
315     
316     rk610_scaler_disable(client);       
317     rk610_scaler_pll_disable(client);
318     
319     return 0;
320 }
321
322 #ifdef CONFIG_HAS_EARLYSUSPEND
323 static void rk610_lcd_early_suspend(struct early_suspend *h)
324 {
325     struct i2c_client *client = g_lcd_inf->client;
326     char c;
327     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
328     if(g_lcd_inf->screen != NULL){
329         rk610_output_config(client,g_lcd_inf->screen,LCD_OUT_DISABLE);
330     }
331
332     if(ENABLE == g_lcd_inf->scl_inf.scl_pwr){
333         c= SCL_BYPASS(1) |SCL_DEN_INV(0) |SCL_H_V_SYNC_INV(0) |SCL_OUT_CLK_INV(0) |SCL_ENABLE(DISABLE); 
334         rk610_scaler_write_p0_reg(client, SCL_CON0, &c);
335     }
336     if(ENABLE == g_lcd_inf->scl_inf.pll_pwr ){
337         c = S_PLL_PWR(1) |S_PLL_RESET(0) |S_PLL_BYPASS(1);
338             rk610_scaler_write_p0_reg(client, S_PLL_CON2, &c);
339     }
340 }
341
342 static void rk610_lcd_early_resume(struct early_suspend *h)
343 {
344     struct i2c_client *client = g_lcd_inf->client;
345     char c;
346     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
347
348     if(g_lcd_inf->screen != NULL){
349         rk610_output_config(client,g_lcd_inf->screen,g_lcd_inf->disp_mode);
350     }
351     if(ENABLE == g_lcd_inf->scl_inf.scl_pwr){
352         c= SCL_BYPASS(0) |SCL_DEN_INV(0) |SCL_H_V_SYNC_INV(0) |SCL_OUT_CLK_INV(0) |SCL_ENABLE(ENABLE);  
353             rk610_scaler_write_p0_reg(client, SCL_CON0, &c);
354     }
355     if(ENABLE == g_lcd_inf->scl_inf.pll_pwr ){
356         c = S_PLL_PWR(1) |S_PLL_RESET(0) |S_PLL_BYPASS(1);
357             rk610_scaler_write_p0_reg(client, S_PLL_CON2, &c);
358     }
359 }
360 #endif
361 int rk610_lcd_scaler_set_param(struct rk29fb_screen *screen,bool enable )//enable:0 bypass 1: scale
362 {
363     int ret=0;
364     struct i2c_client *client = g_lcd_inf->client;
365     if(client == NULL){
366         printk("%s client == NULL FAIL\n",__FUNCTION__);
367         return -1;
368     }
369     if(screen == NULL){
370         printk("%s screen == NULL FAIL\n",__FUNCTION__);
371         return -1;
372     }
373     RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
374     
375     g_lcd_inf->screen = screen;
376     
377 #if defined(CONFIG_HDMI_DUAL_DISP) || defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF)
378     if(enable == 1){
379         g_lcd_inf->disp_mode = LCD_OUT_SCL;
380         rk610_output_config(client,screen,LCD_OUT_SCL);
381         ret = rk610_scaler_chg(client,screen);
382         }
383         else 
384 #endif
385         {
386             g_lcd_inf->disp_mode = LCD_OUT_BYPASS;
387             rk610_output_config(client,screen,LCD_OUT_BYPASS);
388             ret = rk610_lcd_scaler_bypass(client,enable);
389         }
390         return ret;
391 }
392 int rk610_lcd_init(struct rk610_core_info *rk610_core_info)
393 {
394     if(rk610_core_info->client == NULL){
395         printk("%s client == NULL FAIL\n",__FUNCTION__);
396         return -1;
397     }
398     RK610_DBG(&rk610_core_info->client->dev,"%s \n",__FUNCTION__);
399
400     g_lcd_inf = kmalloc(sizeof(struct rk610_lcd_info), GFP_KERNEL);
401     if(!g_lcd_inf)
402     {
403         dev_err(&rk610_core_info->client->dev, ">> rk610 inf kmalloc fail!");
404         return -ENOMEM;
405     }
406     memset(g_lcd_inf, 0, sizeof(struct rk610_lcd_info));
407
408     g_lcd_inf->client= rk610_core_info->client;
409     
410     rk610_core_info->lcd_pdata = (void *)g_lcd_inf;
411 #ifdef CONFIG_HAS_EARLYSUSPEND
412         g_lcd_inf->early_suspend.suspend = rk610_lcd_early_suspend;
413         g_lcd_inf->early_suspend.resume = rk610_lcd_early_resume;
414         g_lcd_inf->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB- 1;
415         register_early_suspend(&g_lcd_inf->early_suspend);
416 #endif
417     g_lcd_inf->scl_inf.pll_pwr = DISABLE;
418     g_lcd_inf->scl_inf.scl_pwr = DISABLE;
419     g_lcd_inf->disp_mode = LCD_OUT_BYPASS;
420     return 0;
421 }
422
423 static int rk610_lcd_probe(struct platform_device *pdev)
424 {
425         struct rk610_core_info *core_info = NULL;
426         rk_screen *screen = NULL;
427
428         core_info = dev_get_drvdata(pdev->dev.parent);
429         if(!core_info)
430         {
431                 dev_err(&pdev->dev,"rk610 core info is null\n");
432                 return -ENODEV;
433         }
434         screen = rk_fb_get_prmry_screen();
435         if(!screen)
436         {
437                 dev_err(&pdev->dev,"the fb prmry screen is null!\n");
438                 return -ENODEV;
439         }
440         
441 #if defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF)
442         screen->sscreen_set = rk610_lcd_scaler_set_param;
443 #endif
444         rk610_lcd_init(core_info);
445         rk610_lcd_scaler_set_param(screen,0);
446
447         return 0;
448         
449 }
450 static int rk610_lcd_remove(struct platform_device *pdev)
451 {
452         
453         return 0;
454 }
455
456 static void rk610_lcd_shutdown(struct platform_device *pdev)
457 {
458         
459         return;
460 }
461
462 static struct platform_driver rk610_lcd_driver = {
463         .driver         = {
464                 .name   = "rk610-lcd",
465                 .owner  = THIS_MODULE,
466         },
467         .probe          = rk610_lcd_probe,
468         .remove         = rk610_lcd_remove,
469         .shutdown       = rk610_lcd_shutdown,
470 };
471
472 static int __init rk610_lcd_module_init(void)
473 {
474         return platform_driver_register(&rk610_lcd_driver);
475 }
476 fs_initcall(rk610_lcd_module_init);
477 static void __exit rk610_lcd_exit(void)
478 {
479         platform_driver_unregister(&rk610_lcd_driver);
480 }
481 module_exit(rk610_lcd_exit);
482