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