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
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
14 //return i2c_master_reg8_recv(client, reg, val, 1, 100*1000) > 0? 0: -EINVAL;
\r
17 static int rk610_scaler_write_p0_reg(struct i2c_client *client, char reg, char *val)
\r
19 return i2c_master_reg8_send(client, reg, val, 1, 100*1000) > 0? 0: -EINVAL;
\r
21 static void rk610_scaler_pll_enable(struct i2c_client *client)
\r
24 RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
\r
26 g_lcd_inf->scl_inf.pll_pwr = ENABLE;
\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
31 static void rk610_scaler_pll_disable(struct i2c_client *client)
\r
34 RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
\r
36 g_lcd_inf->scl_inf.pll_pwr = DISABLE;
\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
41 static void rk610_scaler_enable(struct i2c_client *client)
\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
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
57 static void rk610_scaler_disable(struct i2c_client *client)
\r
60 bool den_inv = 0,hv_sync_inv = 0,clk_inv = 0;
\r
61 RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
\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
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
75 static int rk610_output_config(struct i2c_client *client,struct rk29fb_screen *screen,int mode)
\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
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
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
103 c = LCD1_OUT_ENABLE(LCD1_AS_IN);
\r
104 rk610_scaler_write_p0_reg(client, LCD1_CON, &c);
\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
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
121 RK610_ERR(&client->dev,"RK610 Scaler pll not support rate \n");
\r
123 c = S_PLL_FROM_DIV<<3 | S_PLL_DIV(0);
\r
124 rk610_scaler_write_p0_reg(client, CLOCK_CON0, &c);
\r
126 c = S_DIV_N(N)| S_DIV_OD(OD);
\r
127 rk610_scaler_write_p0_reg(client, S_PLL_CON0, &c);
\r
129 rk610_scaler_write_p0_reg(client, S_PLL_CON1, &c);
\r
130 rk610_scaler_pll_enable(client);
\r
135 static int scale_hv_factor(struct i2c_client *client ,u32 Hin_act, u32 Hout_act, u32 Vin_act, u32 Vout_act)
\r
138 u32 hfactor_f,vfactor_f,scl_factor_f;
\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
148 {hfactor = (int)hfactor_f;}
\r
150 scl_factor_f = Vin_act/Vout_act;
\r
152 {vfactor_f = ((Vin_act-1)*4096)/(Vout_act-1);}
\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
160 {vfactor = (int)vfactor_f;}
\r
162 HV2.scl_h= hfactor;
\r
163 HV2.scl_v= vfactor;
\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
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
177 static int rk610_scaler_fator_config(struct i2c_client *client ,struct rk29fb_screen *screen)
\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
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
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
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
205 RK610_ERR(&client->dev,"RK610 not support dual display at hdmi resolution=%d \n",screen->hdmi_resolution);
\r
211 static int rk610_scaler_output_timing_config(struct i2c_client *client,struct rk29fb_screen *screen)
\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
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
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
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
244 c = SCL_DSP_HS_END(hs_end);
\r
245 rk610_scaler_write_p0_reg(client, SCL_CON11, &c);
\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
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
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
262 c = SCL_DSP_VS_END(vs_end);
\r
263 rk610_scaler_write_p0_reg(client, SCL_CON18, &c);
\r
265 c = SCL_DSP_VACT_ST(v_act_st);
\r
266 rk610_scaler_write_p0_reg(client, SCL_CON19, &c);
\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
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
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
283 c = SCL_V_BORD_ST(v_act_st);
\r
284 rk610_scaler_write_p0_reg(client, SCL_CON26, &c);
\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
293 static int rk610_scaler_chg(struct i2c_client *client ,struct rk29fb_screen *screen)
\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
305 static int rk610_lcd_scaler_bypass(struct i2c_client *client,bool enable)//enable:0 bypass 1: scale
\r
307 RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
\r
309 rk610_scaler_disable(client);
\r
310 rk610_scaler_pll_disable(client);
\r
315 #ifdef CONFIG_HAS_EARLYSUSPEND
\r
316 static void rk610_lcd_early_suspend(struct early_suspend *h)
\r
318 struct i2c_client *client = g_lcd_inf->client;
\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
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
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
335 static void rk610_lcd_early_resume(struct early_suspend *h)
\r
337 struct i2c_client *client = g_lcd_inf->client;
\r
339 RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
\r
341 if(g_lcd_inf->screen != NULL){
\r
342 rk610_output_config(client,g_lcd_inf->screen,g_lcd_inf->disp_mode);
\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
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
354 int rk610_lcd_scaler_set_param(struct rk29fb_screen *screen,bool enable )//enable:0 bypass 1: scale
\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
362 if(screen == NULL){
\r
363 printk("%s screen == NULL FAIL\n",__FUNCTION__);
\r
366 RK610_DBG(&client->dev,"%s \n",__FUNCTION__);
\r
368 g_lcd_inf->screen = screen;
\r
370 #if defined(CONFIG_HDMI_DUAL_DISP) || defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF)
\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
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
385 int rk610_lcd_init(struct rk610_core_info *rk610_core_info)
\r
387 if(rk610_core_info->client == NULL){
\r
388 printk("%s client == NULL FAIL\n",__FUNCTION__);
\r
391 RK610_DBG(&rk610_core_info->client->dev,"%s \n",__FUNCTION__);
\r
393 g_lcd_inf = kmalloc(sizeof(struct rk610_lcd_info), GFP_KERNEL);
\r
396 dev_err(&rk610_core_info->client->dev, ">> rk610 inf kmalloc fail!");
\r
399 memset(g_lcd_inf, 0, sizeof(struct rk610_lcd_info));
\r
401 g_lcd_inf->client= rk610_core_info->client;
\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
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