2 * drivers/video/rockchip/lcdc/rk3188_lcdc.c
\r
4 * Copyright (C) 2013 ROCKCHIP, Inc.
\r
5 *Author:yxj<yxj@rock-chips.com>
\r
6 *This software is licensed under the terms of the GNU General Public
\r
7 * License version 2, as published by the Free Software Foundation, and
\r
8 * may be copied, distributed, and modified under those terms.
\r
10 * This program is distributed in the hope that it will be useful,
\r
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 * GNU General Public License for more details.
\r
17 #include <linux/module.h>
\r
18 #include <linux/kernel.h>
\r
19 #include <linux/errno.h>
\r
20 #include <linux/string.h>
\r
21 #include <linux/mm.h>
\r
22 #include <linux/slab.h>
\r
23 #include <linux/device.h>
\r
24 #include <linux/delay.h>
\r
25 #include <linux/init.h>
\r
26 #include <linux/interrupt.h>
\r
27 #include <linux/platform_device.h>
\r
28 #include <linux/clk.h>
\r
29 #include <linux/earlysuspend.h>
\r
30 #include <asm/div64.h>
\r
31 #include <asm/uaccess.h>
\r
32 #include "rk3188_lcdc.h"
\r
36 static int dbg_thresd = 0;
\r
37 module_param(dbg_thresd, int, S_IRUGO|S_IWUSR);
\r
38 #define DBG(level,x...) do { \
\r
39 if(unlikely(dbg_thresd >= level)) \
\r
40 printk(KERN_INFO x);} while (0)
\r
42 //#define WAIT_FOR_SYNC 1
\r
43 static int rk3188_lcdc_clk_enable(struct rk3188_lcdc_device *lcdc_dev)
\r
46 clk_enable(lcdc_dev->pd);
\r
47 clk_enable(lcdc_dev->hclk);
\r
48 clk_enable(lcdc_dev->dclk);
\r
49 clk_enable(lcdc_dev->aclk);
\r
51 spin_lock(&lcdc_dev->reg_lock);
\r
52 lcdc_dev->clk_on = 1;
\r
53 spin_unlock(&lcdc_dev->reg_lock);
\r
54 printk("rk3188 lcdc%d clk enable...\n",lcdc_dev->id);
\r
59 static int rk3188_lcdc_clk_disable(struct rk3188_lcdc_device *lcdc_dev)
\r
61 spin_lock(&lcdc_dev->reg_lock);
\r
62 lcdc_dev->clk_on = 0;
\r
63 spin_unlock(&lcdc_dev->reg_lock);
\r
65 clk_disable(lcdc_dev->dclk);
\r
66 clk_disable(lcdc_dev->hclk);
\r
67 clk_disable(lcdc_dev->aclk);
\r
68 clk_disable(lcdc_dev->pd);
\r
69 printk("rk3188 lcdc%d clk disable...\n",lcdc_dev->id);
\r
74 static int rk3188_lcdc_resume_reg(struct rk3188_lcdc_device *lcdc_dev)
\r
76 memcpy((u8*)lcdc_dev->regs, (u8*)lcdc_dev->regsbak, 0x84);
\r
81 //enable layer,open:1,enable;0 disable
\r
82 static int win0_open(struct rk3188_lcdc_device *lcdc_dev,bool open)
\r
84 spin_lock(&lcdc_dev->reg_lock);
\r
85 if(likely(lcdc_dev->clk_on))
\r
89 if(!lcdc_dev->atv_layer_cnt)
\r
91 printk(KERN_INFO "lcdc%d wakeup from standby!\n",lcdc_dev->id);
\r
92 lcdc_msk_reg(lcdc_dev, SYS_CTRL,m_LCDC_STANDBY,v_LCDC_STANDBY(0));
\r
94 lcdc_dev->atv_layer_cnt++;
\r
96 else if((lcdc_dev->atv_layer_cnt > 0) && (!open))
\r
98 lcdc_dev->atv_layer_cnt--;
\r
100 lcdc_dev->driver.layer_par[0]->state = open;
\r
102 lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_WIN0_EN, v_WIN0_EN(open));
\r
103 if(!lcdc_dev->atv_layer_cnt) //if no layer used,disable lcdc
\r
105 printk(KERN_INFO "no layer of lcdc%d is used,go to standby!\n",lcdc_dev->id);
\r
106 lcdc_msk_reg(lcdc_dev, SYS_CTRL,m_LCDC_STANDBY,v_LCDC_STANDBY(1));
\r
108 lcdc_cfg_done(lcdc_dev);
\r
110 spin_unlock(&lcdc_dev->reg_lock);
\r
116 static int win1_open(struct rk3188_lcdc_device *lcdc_dev,bool open)
\r
118 spin_lock(&lcdc_dev->reg_lock);
\r
119 if(likely(lcdc_dev->clk_on))
\r
123 if(!lcdc_dev->atv_layer_cnt)
\r
125 printk(KERN_INFO "lcdc%d wakeup from standby!\n",lcdc_dev->id);
\r
126 lcdc_msk_reg(lcdc_dev, SYS_CTRL,m_LCDC_STANDBY,v_LCDC_STANDBY(0));
\r
128 lcdc_dev->atv_layer_cnt++;
\r
130 else if((lcdc_dev->atv_layer_cnt > 0) && (!open))
\r
132 lcdc_dev->atv_layer_cnt--;
\r
134 lcdc_dev->driver.layer_par[1]->state = open;
\r
136 lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_WIN1_EN, v_WIN1_EN(open));
\r
137 if(!lcdc_dev->atv_layer_cnt) //if no layer used,disable lcdc
\r
139 printk(KERN_INFO "no layer of lcdc%d is used,go to standby!\n",lcdc_dev->id);
\r
140 lcdc_msk_reg(lcdc_dev, SYS_CTRL,m_LCDC_STANDBY,v_LCDC_STANDBY(1));
\r
142 lcdc_cfg_done(lcdc_dev);
\r
144 spin_unlock(&lcdc_dev->reg_lock);
\r
149 static int rk3188_lcdc_open(struct rk_lcdc_device_driver *dev_drv,int layer_id,bool open)
\r
154 struct rk3188_lcdc_device *lcdc_dev =
\r
155 container_of(dev_drv,struct rk3188_lcdc_device,driver);
\r
157 if((open) && (!lcdc_dev->atv_layer_cnt)) //enable clk,when first layer open
\r
159 rk3188_lcdc_clk_enable(lcdc_dev);
\r
160 rk3188_lcdc_resume_reg(lcdc_dev); //resume reg
\r
161 spin_lock(&lcdc_dev->reg_lock);
\r
162 if(dev_drv->cur_screen->dsp_lut) //resume dsp lut
\r
164 lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_DSP_LUT_EN,v_DSP_LUT_EN(0));
\r
165 lcdc_cfg_done(lcdc_dev);
\r
166 mdelay(25); //wait for dsp lut disabled
\r
169 v = dev_drv->cur_screen->dsp_lut[i];
\r
170 c = lcdc_dev->dsp_lut_addr_base+i;
\r
171 writel_relaxed(v,c);
\r
174 lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_DSP_LUT_EN,v_DSP_LUT_EN(1)); //enable dsp lut
\r
176 spin_unlock(&lcdc_dev->reg_lock);
\r
181 win0_open(lcdc_dev,open);
\r
183 else if(layer_id == 1)
\r
185 win1_open(lcdc_dev,open);
\r
189 printk("invalid win number:%d\n",layer_id);
\r
192 if((!open) && (!lcdc_dev->atv_layer_cnt)) //when all layer closed,disable clk
\r
194 rk3188_lcdc_clk_disable(lcdc_dev);
\r
197 printk(KERN_INFO "lcdc%d win%d %s,atv layer:%d\n",
\r
198 lcdc_dev->id,layer_id,open?"open":"closed",
\r
199 lcdc_dev->atv_layer_cnt);
\r
203 static int rk3188_lcdc_init(struct rk_lcdc_device_driver *dev_drv)
\r
208 struct rk3188_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk3188_lcdc_device,driver);
\r
209 if(lcdc_dev->id == 0) //lcdc0
\r
211 lcdc_dev->pd = clk_get(NULL,"pd_lcdc0");
\r
212 lcdc_dev->hclk = clk_get(NULL,"hclk_lcdc0");
\r
213 lcdc_dev->aclk = clk_get(NULL,"aclk_lcdc0");
\r
214 lcdc_dev->dclk = clk_get(NULL,"dclk_lcdc0");
\r
216 else if(lcdc_dev->id == 1)
\r
218 lcdc_dev->pd = clk_get(NULL,"pd_lcdc1");
\r
219 lcdc_dev->hclk = clk_get(NULL,"hclk_lcdc1");
\r
220 lcdc_dev->aclk = clk_get(NULL,"aclk_lcdc1");
\r
221 lcdc_dev->dclk = clk_get(NULL,"dclk_lcdc1");
\r
225 printk(KERN_ERR "invalid lcdc device!\n");
\r
228 if (IS_ERR(lcdc_dev->pd) || (IS_ERR(lcdc_dev->aclk)) ||(IS_ERR(lcdc_dev->dclk)) || (IS_ERR(lcdc_dev->hclk)))
\r
230 printk(KERN_ERR "failed to get lcdc%d clk source\n",lcdc_dev->id);
\r
233 rk3188_lcdc_clk_enable(lcdc_dev);
\r
235 lcdc_set_bit(lcdc_dev,SYS_CTRL,m_AUTO_GATING_EN);//eanble axi-clk auto gating for low power
\r
236 if(dev_drv->cur_screen->dsp_lut)
\r
238 lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_DSP_LUT_EN,v_DSP_LUT_EN(0));
\r
239 lcdc_cfg_done(lcdc_dev);
\r
243 v = dev_drv->cur_screen->dsp_lut[i];
\r
244 c = lcdc_dev->dsp_lut_addr_base+i;
\r
245 writel_relaxed(v,c);
\r
248 lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_DSP_LUT_EN,v_DSP_LUT_EN(1));
\r
251 lcdc_cfg_done(lcdc_dev); // write any value to REG_CFG_DONE let config become effective
\r
253 rk3188_lcdc_clk_disable(lcdc_dev);
\r
259 //set lcdc according the screen info
\r
260 static int rk3188_load_screen(struct rk_lcdc_device_driver *dev_drv, bool initscreen)
\r
265 struct rk3188_lcdc_device *lcdc_dev =
\r
266 container_of(dev_drv,struct rk3188_lcdc_device,driver);
\r
267 rk_screen *screen = dev_drv->cur_screen;
\r
268 u16 right_margin = screen->right_margin;
\r
269 u16 left_margin = screen->left_margin;
\r
270 u16 lower_margin = screen->lower_margin;
\r
271 u16 upper_margin = screen->upper_margin;
\r
272 u16 x_res = screen->x_res;
\r
273 u16 y_res = screen->y_res;
\r
276 spin_lock(&lcdc_dev->reg_lock);
\r
277 if(likely(lcdc_dev->clk_on))
\r
279 if(screen->type==SCREEN_MCU)
\r
281 printk("MUC¡¡screen not supported now!\n");
\r
285 switch (screen->face)
\r
288 face = OUT_P565; //dither down to rgb565
\r
289 lcdc_msk_reg(lcdc_dev, DSP_CTRL0, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(0));
\r
292 face = OUT_P666; //dither down to rgb666
\r
293 lcdc_msk_reg(lcdc_dev, DSP_CTRL0, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(1));
\r
295 case OUT_D888_P565:
\r
297 lcdc_msk_reg(lcdc_dev, DSP_CTRL0, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(0));
\r
299 case OUT_D888_P666:
\r
301 lcdc_msk_reg(lcdc_dev, DSP_CTRL0, m_DITHER_DOWN_EN | m_DITHER_DOWN_MODE, v_DITHER_DOWN_EN(1) | v_DITHER_DOWN_MODE(1));
\r
307 printk("unsupported display output interface!\n");
\r
311 //use default overlay,set vsyn hsync den dclk polarity
\r
312 lcdc_msk_reg(lcdc_dev, DSP_CTRL0,m_DSP_OUT_FORMAT | m_HSYNC_POL | m_VSYNC_POL |
\r
313 m_DEN_POL |m_DCLK_POL,v_DSP_OUT_FORMAT(face) | v_HSYNC_POL(screen->pin_hsync) |
\r
314 v_VSYNC_POL(screen->pin_vsync) | v_DEN_POL(screen->pin_den) | v_DCLK_POL(screen->pin_dclk));
\r
317 //set background color to black,set swap according to the screen panel,disable blank mode
\r
318 lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_BG_COLOR| m_DSP_BG_SWAP | m_DSP_RB_SWAP |
\r
319 m_DSP_RG_SWAP | m_DSP_DELTA_SWAP | m_DSP_DUMMY_SWAP | m_BLANK_EN,
\r
320 v_BG_COLOR(0x000000) | v_DSP_BG_SWAP(screen->swap_bg) |
\r
321 v_DSP_RB_SWAP(screen->swap_rb) | v_DSP_RG_SWAP(screen->swap_rg) |
\r
322 v_DSP_DELTA_SWAP(screen->swap_delta) | v_DSP_DUMMY_SWAP(screen->swap_dumy) |
\r
323 v_BLANK_EN(0) | v_BLACK_EN(0));
\r
324 lcdc_writel(lcdc_dev,DSP_HTOTAL_HS_END,v_HSYNC(screen->hsync_len) |
\r
325 v_HORPRD(screen->hsync_len + left_margin + x_res + right_margin));
\r
326 lcdc_writel(lcdc_dev,DSP_HACT_ST_END,v_HAEP(screen->hsync_len + left_margin + x_res) |
\r
327 v_HASP(screen->hsync_len + left_margin));
\r
329 lcdc_writel(lcdc_dev,DSP_VTOTAL_VS_END, v_VSYNC(screen->vsync_len) |
\r
330 v_VERPRD(screen->vsync_len + upper_margin + y_res + lower_margin));
\r
331 lcdc_writel(lcdc_dev,DSP_VACT_ST_END,v_VAEP(screen->vsync_len + upper_margin+y_res)|
\r
332 v_VASP(screen->vsync_len + screen->upper_margin));
\r
334 spin_unlock(&lcdc_dev->reg_lock);
\r
336 ret = clk_set_rate(lcdc_dev->dclk, screen->pixclock);
\r
339 dev_err(dev_drv->dev,"set lcdc%d dclk failed\n",lcdc_dev->id);
\r
341 lcdc_dev->driver.pixclock = lcdc_dev->pixclock = div_u64(1000000000000llu, clk_get_rate(lcdc_dev->dclk));
\r
343 fps = rk_fb_calc_fps(screen,lcdc_dev->pixclock);
\r
344 screen->ft = 1000/fps;
\r
345 printk("%s: dclk:%lu>>fps:%d ",lcdc_dev->driver.name,clk_get_rate(lcdc_dev->dclk),fps);
\r
352 dev_info(dev_drv->dev,"%s for lcdc%d ok!\n",__func__,lcdc_dev->id);
\r
357 static int win0_set_par(struct rk3188_lcdc_device *lcdc_dev,rk_screen *screen,
\r
358 struct layer_par *par )
\r
360 u32 xact, yact, xvir, yvir, xpos, ypos;
\r
361 u32 ScaleYrgbX = 0x1000;
\r
362 u32 ScaleYrgbY = 0x1000;
\r
363 u32 ScaleCbrX = 0x1000;
\r
364 u32 ScaleCbrY = 0x1000;
\r
366 xact = par->xact; //active (origin) picture window width/height
\r
368 xvir = par->xvir; // virtual resolution
\r
370 xpos = par->xpos+screen->left_margin + screen->hsync_len;
\r
371 ypos = par->ypos+screen->upper_margin + screen->vsync_len;
\r
374 ScaleYrgbX = CalScale(xact, par->xsize); //both RGB and yuv need this two factor
\r
375 ScaleYrgbY = CalScale(yact, par->ysize);
\r
376 switch (par->format)
\r
378 case YUV422:// yuv422
\r
379 ScaleCbrX = CalScale((xact/2), par->xsize);
\r
380 ScaleCbrY = CalScale(yact, par->ysize);
\r
382 case YUV420: // yuv420
\r
383 ScaleCbrX = CalScale(xact/2, par->xsize);
\r
384 ScaleCbrY = CalScale(yact/2, par->ysize);
\r
386 case YUV444:// yuv444
\r
387 ScaleCbrX = CalScale(xact, par->xsize);
\r
388 ScaleCbrY = CalScale(yact, par->ysize);
\r
394 DBG(1,"%s for lcdc%d>>format:%d>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d>>xvir:%d>>yvir:%d>>xpos:%d>>ypos:%d>>\n",
\r
395 __func__,lcdc_dev->id,par->format,xact,yact,par->xsize,par->ysize,xvir,yvir,xpos,ypos);
\r
397 spin_lock(&lcdc_dev->reg_lock);
\r
398 if(likely(lcdc_dev->clk_on))
\r
400 lcdc_writel(lcdc_dev,WIN0_SCL_FACTOR_YRGB,v_X_SCL_FACTOR(ScaleYrgbX) | v_Y_SCL_FACTOR(ScaleYrgbY));
\r
401 lcdc_writel(lcdc_dev,WIN0_SCL_FACTOR_CBR,v_X_SCL_FACTOR(ScaleCbrX) | v_Y_SCL_FACTOR(ScaleCbrY));
\r
402 lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_WIN0_FORMAT,v_WIN0_FORMAT(par->format)); //(inf->video_mode==0)
\r
403 lcdc_writel(lcdc_dev,WIN0_ACT_INFO,v_ACT_WIDTH(xact) | v_ACT_HEIGHT(yact));
\r
404 lcdc_writel(lcdc_dev,WIN0_DSP_ST,v_DSP_STX(xpos) | v_DSP_STY(ypos));
\r
405 lcdc_writel(lcdc_dev,WIN0_DSP_INFO,v_DSP_WIDTH(par->xsize) | v_DSP_HEIGHT(par->ysize));
\r
406 lcdc_msk_reg(lcdc_dev,WIN0_COLOR_KEY,m_COLOR_KEY_EN,v_COLOR_KEY_EN(0));
\r
408 switch(par->format)
\r
411 lcdc_msk_reg(lcdc_dev, WIN_VIR,m_WIN0_VIR,v_ARGB888_VIRWIDTH(xvir));
\r
412 //lcdc_msk_reg(lcdc_dev,SYS_CTRL1,m_W0_RGB_RB_SWAP,v_W0_RGB_RB_SWAP(1));
\r
414 case RGB888: //rgb888
\r
415 lcdc_msk_reg(lcdc_dev, WIN_VIR,m_WIN0_VIR,v_RGB888_VIRWIDTH(xvir));
\r
416 //lcdc_msk_reg(lcdc_dev,SYS_CTRL1,m_W0_RGB_RB_SWAP,v_W0_RGB_RB_SWAP(1));
\r
418 case RGB565: //rgb565
\r
419 lcdc_msk_reg(lcdc_dev, WIN_VIR,m_WIN0_VIR,v_RGB565_VIRWIDTH(xvir));
\r
424 lcdc_msk_reg(lcdc_dev, WIN_VIR,m_WIN0_VIR,v_YUV_VIRWIDTH(xvir));
\r
427 dev_err(lcdc_dev->driver.dev,"un supported format!\n");
\r
432 spin_unlock(&lcdc_dev->reg_lock);
\r
438 static int win1_set_par(struct rk3188_lcdc_device *lcdc_dev,rk_screen *screen,
\r
439 struct layer_par *par )
\r
441 u32 xact, yact, xvir, yvir, xpos, ypos;
\r
447 xpos = par->xpos+screen->left_margin + screen->hsync_len;
\r
448 ypos = par->ypos+screen->upper_margin + screen->vsync_len;
\r
451 DBG(1,"%s for lcdc%d>>format:%d>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d>>xvir:%d>>yvir:%d>>xpos:%d>>ypos:%d>>\n",
\r
452 __func__,lcdc_dev->id,par->format,xact,yact,par->xsize,par->ysize,xvir,yvir,xpos,ypos);
\r
455 spin_lock(&lcdc_dev->reg_lock);
\r
456 if(likely(lcdc_dev->clk_on))
\r
458 lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_WIN1_FORMAT, v_WIN1_FORMAT(par->format));
\r
459 lcdc_writel(lcdc_dev, WIN1_DSP_INFO,v_DSP_WIDTH(par->xsize) | v_DSP_HEIGHT(par->ysize));
\r
460 lcdc_writel(lcdc_dev, WIN1_DSP_ST,v_DSP_STX(xpos) | v_DSP_STY(ypos));
\r
461 // disable win1 color key and set the color to black(rgb=0)
\r
462 lcdc_msk_reg(lcdc_dev, WIN1_COLOR_KEY,m_COLOR_KEY_EN,v_COLOR_KEY_EN(0));
\r
463 switch(par->format)
\r
466 lcdc_msk_reg(lcdc_dev, WIN_VIR,m_WIN1_VIR,v_WIN1_ARGB888_VIRWIDTH(xvir));
\r
467 //lcdc_msk_reg(lcdc_dev,SYS_CTRL1,m_W1_RGB_RB_SWAP,v_W1_RGB_RB_SWAP(1));
\r
469 case RGB888: //rgb888
\r
470 lcdc_msk_reg(lcdc_dev, WIN_VIR,m_WIN1_VIR,v_WIN1_RGB888_VIRWIDTH(xvir));
\r
471 // lcdc_msk_reg(lcdc_dev,SYS_CTRL1,m_W1_RGB_RB_SWAP,v_W1_RGB_RB_SWAP(1));
\r
473 case RGB565: //rgb565
\r
474 lcdc_msk_reg(lcdc_dev, WIN_VIR,m_WIN1_VIR,v_WIN1_RGB565_VIRWIDTH(xvir));
\r
477 dev_err(lcdc_dev->driver.dev,"un supported format!\n");
\r
482 spin_unlock(&lcdc_dev->reg_lock);
\r
488 static int rk3188_lcdc_set_par(struct rk_lcdc_device_driver *dev_drv,int layer_id)
\r
490 struct rk3188_lcdc_device *lcdc_dev =
\r
491 container_of(dev_drv,struct rk3188_lcdc_device,driver);
\r
492 struct layer_par *par = NULL;
\r
493 rk_screen *screen = dev_drv->cur_screen;
\r
497 dev_err(dev_drv->dev,"screen is null!\n");
\r
502 par = dev_drv->layer_par[0];
\r
503 win0_set_par(lcdc_dev,screen,par);
\r
505 else if(layer_id==1)
\r
507 par = dev_drv->layer_par[1];
\r
508 win1_set_par(lcdc_dev,screen,par);
\r
512 dev_err(dev_drv->dev,"unsupported win number:%d\n",layer_id);
\r
519 static int win0_display(struct rk3188_lcdc_device *lcdc_dev,struct layer_par *par )
\r
523 y_addr = par->smem_start + par->y_offset;
\r
524 uv_addr = par->cbr_start + par->c_offset;
\r
525 DBG(2,KERN_INFO "lcdc%d>>%s:y_addr:0x%x>>uv_addr:0x%x\n",lcdc_dev->id,__func__,y_addr,uv_addr);
\r
527 spin_lock(&lcdc_dev->reg_lock);
\r
528 if(likely(lcdc_dev->clk_on))
\r
530 lcdc_writel(lcdc_dev, WIN0_YRGB_MST0, y_addr);
\r
531 lcdc_writel(lcdc_dev, WIN0_CBR_MST0, uv_addr);
\r
532 lcdc_cfg_done(lcdc_dev);
\r
534 spin_unlock(&lcdc_dev->reg_lock);
\r
540 static int win1_display(struct rk3188_lcdc_device *lcdc_dev,struct layer_par *par )
\r
544 y_addr = par->smem_start + par->y_offset;
\r
545 uv_addr = par->cbr_start + par->c_offset;
\r
546 DBG(2,KERN_INFO "lcdc%d>>%s>>y_addr:0x%x>>uv_addr:0x%x\n",lcdc_dev->id,__func__,y_addr,uv_addr);
\r
548 spin_lock(&lcdc_dev->reg_lock);
\r
549 if(likely(lcdc_dev->clk_on))
\r
551 lcdc_writel(lcdc_dev,WIN1_MST,y_addr);
\r
552 lcdc_cfg_done(lcdc_dev);
\r
554 spin_unlock(&lcdc_dev->reg_lock);
\r
559 static int rk3188_lcdc_pan_display(struct rk_lcdc_device_driver * dev_drv,int layer_id)
\r
561 struct rk3188_lcdc_device *lcdc_dev =
\r
562 container_of(dev_drv,struct rk3188_lcdc_device,driver);
\r
563 struct layer_par *par = NULL;
\r
564 rk_screen *screen = dev_drv->cur_screen;
\r
565 unsigned long flags;
\r
570 dev_err(dev_drv->dev,"screen is null!\n");
\r
575 par = dev_drv->layer_par[0];
\r
576 win0_display(lcdc_dev,par);
\r
578 else if(layer_id==1)
\r
580 par = dev_drv->layer_par[1];
\r
581 win1_display(lcdc_dev,par);
\r
585 dev_err(dev_drv->dev,"invalid win number:%d!\n",layer_id);
\r
588 if((dev_drv->first_frame)) //this is the first frame of the system ,enable frame start interrupt
\r
590 dev_drv->first_frame = 0;
\r
591 lcdc_msk_reg(lcdc_dev,INT_STATUS,m_FS_INT_CLEAR |m_FS_INT_EN ,
\r
592 v_FS_INT_CLEAR(1) | v_FS_INT_EN(1));
\r
593 lcdc_cfg_done(lcdc_dev); // write any value to REG_CFG_DONE let config become effective
\r
597 #if defined(WAIT_FOR_SYNC)
\r
598 spin_lock_irqsave(&dev_drv->cpl_lock,flags);
\r
599 init_completion(&dev_drv->frame_done);
\r
600 spin_unlock_irqrestore(&dev_drv->cpl_lock,flags);
\r
601 timeout = wait_for_completion_timeout(&dev_drv->frame_done,msecs_to_jiffies(dev_drv->cur_screen->ft+5));
\r
602 if(!timeout&&(!dev_drv->frame_done.done))
\r
604 printk(KERN_ERR "wait for new frame start time out!\n");
\r
611 static int rk3188_lcdc_blank(struct rk_lcdc_device_driver *dev_drv,
\r
612 int layer_id,int blank_mode)
\r
618 static int rk3188_lcdc_ioctl(struct rk_lcdc_device_driver *dev_drv, unsigned int cmd,unsigned long arg,int layer_id)
\r
623 static int rk3188_lcdc_early_suspend(struct rk_lcdc_device_driver *dev_drv)
\r
628 static int rk3188_lcdc_early_resume(struct rk_lcdc_device_driver *dev_drv)
\r
633 static int rk3188_lcdc_get_layer_state(struct rk_lcdc_device_driver *dev_drv,int layer_id)
\r
638 static int rk3188_lcdc_ovl_mgr(struct rk_lcdc_device_driver *dev_drv,int swap,bool set)
\r
643 static ssize_t rk3188_lcdc_get_disp_info(struct rk_lcdc_device_driver *dev_drv,char *buf,int layer_id)
\r
648 static int rk3188_lcdc_fps_mgr(struct rk_lcdc_device_driver *dev_drv,int fps,bool set)
\r
654 static int rk3188_fb_layer_remap(struct rk_lcdc_device_driver *dev_drv,
\r
655 enum fb_win_map_order order)
\r
657 mutex_lock(&dev_drv->fb_win_id_mutex);
\r
658 if(order == FB_DEFAULT_ORDER )
\r
660 order = FB0_WIN0_FB1_WIN1_FB2_WIN2;
\r
662 dev_drv->fb2_win_id = order/100;
\r
663 dev_drv->fb1_win_id = (order/10)%10;
\r
664 dev_drv->fb0_win_id = order%10;
\r
665 mutex_unlock(&dev_drv->fb_win_id_mutex);
\r
667 printk("fb0:win%d\nfb1:win%d\nfb2:win%d\n",dev_drv->fb0_win_id,dev_drv->fb1_win_id,
\r
668 dev_drv->fb2_win_id);
\r
673 static int rk3188_fb_get_layer(struct rk_lcdc_device_driver *dev_drv,const char *id)
\r
676 mutex_lock(&dev_drv->fb_win_id_mutex);
\r
677 if(!strcmp(id,"fb0")||!strcmp(id,"fb2"))
\r
679 layer_id = dev_drv->fb0_win_id;
\r
681 else if(!strcmp(id,"fb1")||!strcmp(id,"fb3"))
\r
683 layer_id = dev_drv->fb1_win_id;
\r
685 mutex_unlock(&dev_drv->fb_win_id_mutex);
\r
690 static int rk3188_set_dsp_lut(struct rk_lcdc_device_driver *dev_drv,int *lut)
\r
697 struct rk3188_lcdc_device *lcdc_dev =
\r
698 container_of(dev_drv,struct rk3188_lcdc_device,driver);
\r
699 lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_DSP_LUT_EN,v_DSP_LUT_EN(0));
\r
700 lcdc_cfg_done(lcdc_dev);
\r
702 if(dev_drv->cur_screen->dsp_lut)
\r
706 v = dev_drv->cur_screen->dsp_lut[i] = lut[i];
\r
707 c = lcdc_dev->dsp_lut_addr_base+i;
\r
708 writel_relaxed(v,c);
\r
714 dev_err(dev_drv->dev,"no buffer to backup lut data!\n");
\r
717 lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_DSP_LUT_EN,v_DSP_LUT_EN(1));
\r
718 lcdc_cfg_done(lcdc_dev);
\r
723 static struct layer_par lcdc_layer[] = {
\r
727 .support_3d = true,
\r
732 .support_3d = false,
\r
736 static struct rk_lcdc_device_driver lcdc_driver = {
\r
738 .def_layer_par = lcdc_layer,
\r
739 .num_layer = ARRAY_SIZE(lcdc_layer),
\r
740 .open = rk3188_lcdc_open,
\r
741 .init_lcdc = rk3188_lcdc_init,
\r
742 .load_screen = rk3188_load_screen,
\r
743 .set_par = rk3188_lcdc_set_par,
\r
744 .pan_display = rk3188_lcdc_pan_display,
\r
745 .blank = rk3188_lcdc_blank,
\r
746 .ioctl = rk3188_lcdc_ioctl,
\r
747 .suspend = rk3188_lcdc_early_suspend,
\r
748 .resume = rk3188_lcdc_early_resume,
\r
749 .get_layer_state = rk3188_lcdc_get_layer_state,
\r
750 .ovl_mgr = rk3188_lcdc_ovl_mgr,
\r
751 .get_disp_info = rk3188_lcdc_get_disp_info,
\r
752 .fps_mgr = rk3188_lcdc_fps_mgr,
\r
753 .fb_get_layer = rk3188_fb_get_layer,
\r
754 .fb_layer_remap = rk3188_fb_layer_remap,
\r
755 .set_dsp_lut = rk3188_set_dsp_lut,
\r
758 static irqreturn_t rk3188_lcdc_isr(int irq, void *dev_id)
\r
760 struct rk3188_lcdc_device *lcdc_dev =
\r
761 (struct rk3188_lcdc_device *)dev_id;
\r
763 lcdc_msk_reg(lcdc_dev, INT_STATUS, m_FS_INT_CLEAR, v_FS_INT_CLEAR(1));
\r
765 #if defined(WAIT_FOR_SYNC)
\r
766 if(lcdc_dev->driver.num_buf < 3) //three buffer ,no need to wait for sync
\r
768 spin_lock(&(lcdc_dev->driver.cpl_lock));
\r
769 complete(&(lcdc_dev->driver.frame_done));
\r
770 spin_unlock(&(lcdc_dev->driver.cpl_lock));
\r
773 return IRQ_HANDLED;
\r
777 #if defined(CONFIG_PM)
\r
778 static int rk3188_lcdc_suspend(struct platform_device *pdev,
\r
779 pm_message_t state)
\r
784 static int rk3188_lcdc_resume(struct platform_device *pdev)
\r
789 #define rk3188_lcdc_suspend NULL
\r
790 #define rk3188_lcdc_resume NULL
\r
792 static int __devinit rk3188_lcdc_probe(struct platform_device *pdev)
\r
794 struct rk3188_lcdc_device *lcdc_dev = NULL;
\r
795 struct device *dev = &pdev->dev;
\r
797 struct rk29fb_info *screen_ctr_info;
\r
798 struct resource *res = NULL;
\r
799 struct resource *mem = NULL;
\r
802 lcdc_dev = devm_kzalloc(dev,sizeof(struct rk3188_lcdc_device), GFP_KERNEL);
\r
805 dev_err(&pdev->dev, ">>rk3188 lcdc device kmalloc fail!");
\r
808 platform_set_drvdata(pdev, lcdc_dev);
\r
809 lcdc_dev->id = pdev->id;
\r
810 screen_ctr_info = (struct rk29fb_info * )pdev->dev.platform_data;
\r
811 if(!screen_ctr_info)
\r
813 dev_err(dev, "no platform data specified for screen control info!\n");
\r
817 screen = kzalloc(sizeof(rk_screen), GFP_KERNEL);
\r
820 dev_err(&pdev->dev, "rk screen kmalloc fail!");
\r
825 res = platform_get_resource(pdev, IORESOURCE_MEM,0);
\r
828 dev_err(&pdev->dev, "failed to get register resource for lcdc%d \n",lcdc_dev->id);
\r
833 lcdc_dev->reg_phy_base = res->start;
\r
834 lcdc_dev->len = resource_size(res);
\r
835 mem = request_mem_region(lcdc_dev->reg_phy_base,lcdc_dev->len, pdev->name);
\r
838 dev_err(&pdev->dev, "failed to request mem region for lcdc%d\n",lcdc_dev->id);
\r
842 lcdc_dev->regs = ioremap(lcdc_dev->reg_phy_base,lcdc_dev->len);
\r
843 if (!lcdc_dev->regs)
\r
845 dev_err(&pdev->dev, "cannot map register for lcdc%d\n",lcdc_dev->id);
\r
850 lcdc_dev->regsbak = kzalloc(lcdc_dev->len,GFP_KERNEL);
\r
851 if(!lcdc_dev->regsbak)
\r
853 dev_err(&pdev->dev, "failed to map memory for reg backup!\n");
\r
857 lcdc_dev->dsp_lut_addr_base = (lcdc_dev->regs + DSP_LUT_ADDR);
\r
858 printk("lcdc%d:reg_phy_base = 0x%08x,reg_vir_base:0x%p\n",pdev->id,lcdc_dev->reg_phy_base, lcdc_dev->regs);
\r
859 lcdc_dev->driver.dev = dev;
\r
860 lcdc_dev->driver.screen0 = screen;
\r
861 lcdc_dev->driver.cur_screen = screen;
\r
862 lcdc_dev->driver.screen_ctr_info = screen_ctr_info;
\r
864 spin_lock_init(&lcdc_dev->reg_lock);
\r
866 lcdc_dev->irq = platform_get_irq(pdev, 0);
\r
867 if(lcdc_dev->irq < 0)
\r
869 dev_err(&pdev->dev, "cannot find IRQ for lcdc%d\n",lcdc_dev->id);
\r
872 ret = devm_request_irq(dev,lcdc_dev->irq, rk3188_lcdc_isr, IRQF_DISABLED,dev_name(dev),lcdc_dev);
\r
875 dev_err(&pdev->dev, "cannot requeset irq %d - err %d\n", lcdc_dev->irq, ret);
\r
879 ret = rk_fb_register(&(lcdc_dev->driver),&lcdc_driver,lcdc_dev->id);
\r
882 dev_err(dev,"register fb for lcdc%d failed!\n",lcdc_dev->id);
\r
885 printk("rk3188 lcdc%d probe ok!\n",lcdc_dev->id);
\r
888 free_irq(lcdc_dev->irq,lcdc_dev);
\r
890 iounmap(lcdc_dev->regs);
\r
892 release_mem_region(lcdc_dev->reg_phy_base,lcdc_dev->len);
\r
896 platform_set_drvdata(pdev, NULL);
\r
902 static int __devexit rk3188_lcdc_remove(struct platform_device *pdev)
\r
907 static void rk3188_lcdc_shutdown(struct platform_device *pdev)
\r
911 static struct platform_driver rk3188_lcdc_driver = {
\r
912 .probe = rk3188_lcdc_probe,
\r
913 .remove = __devexit_p(rk3188_lcdc_remove),
\r
915 .name = "rk3188-lcdc",
\r
916 .owner = THIS_MODULE,
\r
918 .suspend = rk3188_lcdc_suspend,
\r
919 .resume = rk3188_lcdc_resume,
\r
920 .shutdown = rk3188_lcdc_shutdown,
\r
922 static int __init rk3188_lcdc_module_init(void)
\r
924 return platform_driver_register(&rk3188_lcdc_driver);
\r
927 static void __exit rk3188_lcdc_module_exit(void)
\r
929 platform_driver_unregister(&rk3188_lcdc_driver);
\r
931 fs_initcall(rk3188_lcdc_module_init);
\r
932 module_exit(rk3188_lcdc_module_exit);
\r