From 115b4fda26ce62168f6ab0922933c4a2b8017346 Mon Sep 17 00:00:00 2001 From: zwl Date: Fri, 15 Aug 2014 11:52:06 +0800 Subject: [PATCH] rk fb: add support scaler for one lcdc dual disp mode --- drivers/video/rockchip/lcdc/rk312x_lcdc.c | 19 ++++--- drivers/video/rockchip/rk_fb.c | 65 +++++++++++++++++------ 2 files changed, 61 insertions(+), 23 deletions(-) diff --git a/drivers/video/rockchip/lcdc/rk312x_lcdc.c b/drivers/video/rockchip/lcdc/rk312x_lcdc.c index 3b2af29373b4..9d6599b00784 100755 --- a/drivers/video/rockchip/lcdc/rk312x_lcdc.c +++ b/drivers/video/rockchip/lcdc/rk312x_lcdc.c @@ -581,7 +581,7 @@ static u32 calc_sclk(struct rk_screen *src_screen, struct rk_screen *dst_screen) u64 dsp_htotal; u32 dsp_in_vtotal; u64 dsp_in_htotal; - u32 sclk; + u64 sclk; if (!src_screen || !dst_screen) return 0; @@ -596,7 +596,7 @@ static u32 calc_sclk(struct rk_screen *src_screen, struct rk_screen *dst_screen) sclk = dsp_vtotal * dsp_htotal * src_screen->mode.pixclock; do_div(sclk, dsp_in_vtotal * dsp_in_htotal); - return sclk; + return (u32)sclk; } static int calc_dsp_frm_vst_hst(struct rk_screen *src, struct rk_screen *dst) @@ -689,9 +689,14 @@ static int rk312x_lcdc_set_scaler(struct rk_lcdc_driver *dev_drv, if (unlikely(!lcdc_dev->clk_on)) return 0; - if(!enable) { + if (!enable) { + spin_lock(&lcdc_dev->reg_lock); + lcdc_msk_reg(lcdc_dev, SCALER_CTRL, + m_SCALER_EN | m_SCALER_OUT_ZERO | m_SCALER_OUT_EN, + v_SCALER_EN(0) | v_SCALER_OUT_ZERO(0) | v_SCALER_OUT_EN(0)); + spin_unlock(&lcdc_dev->reg_lock); clk_disable_unprepare(lcdc_dev->sclk); - dev_info(lcdc_dev->dev, "%s: disable\n", __func__); + dev_dbg(lcdc_dev->dev, "%s: disable\n", __func__); return 0; } @@ -700,16 +705,16 @@ static int rk312x_lcdc_set_scaler(struct rk_lcdc_driver *dev_drv, * prmry screen is used for scaler dst */ dst = dst_screen; - if (!dst) { + src = dev_drv->cur_screen; + if (!dst || !src) { dev_err(lcdc_dev->dev, "%s: dst screen is null!\n", __func__); return -EINVAL; } - src = dst_screen->ext_screen; - clk_prepare_enable(lcdc_dev->sclk); lcdc_dev->s_pixclock = calc_sclk(src, dst); clk_set_rate(lcdc_dev->sclk, lcdc_dev->s_pixclock); + dev_info(lcdc_dev->dev, "%s:sclk=%d\n", __func__, lcdc_dev->s_pixclock); /* config scale timing */ calc_dsp_frm_vst_hst(src, dst); diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index eb8526115ce3..d22053b71b58 100755 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -615,20 +615,30 @@ int rk_fb_set_prmry_screen_status(int status) return 0; } +/* + * function: this function will be called by display device, + * set cur_screen size scaler to the other screen size + * @screen: the screen info that is the destination + * @enable: + * 0: no scaler and set the screen info as 'screen' parameter + * 1: set scaler and set the src screen scaler to the dst screen + */ static int rk_fb_set_screen_scaler(struct rk_screen *screen, bool enable) { - struct rk_lcdc_driver *dev_drv = rk_get_prmry_lcdc_drv(); + struct rk_lcdc_driver *dev_drv = rk_get_prmry_lcdc_drv(); - if(unlikely(!dev_drv) || unlikely(!screen)) - return -1; - if (!enable) - return 0; + if (unlikely(!dev_drv) || unlikely(!screen)) + return -1; - rk_fb_set_prmry_screen_status(SCREEN_PREPARE_DDR_CHANGE); - if (dev_drv->ops->set_screen_scaler) - dev_drv->ops->set_screen_scaler(dev_drv, screen, enable); - rk_fb_set_prmry_screen_status(SCREEN_UNPREPARE_DDR_CHANGE); - return 0; + rk_fb_set_prmry_screen_status(SCREEN_PREPARE_DDR_CHANGE); + if (dev_drv->ops->set_screen_scaler) + dev_drv->ops->set_screen_scaler(dev_drv, screen, enable); + if (!enable) { + memcpy(dev_drv->cur_screen, screen, sizeof(struct rk_screen)); + dev_drv->ops->load_screen(dev_drv, 1); + } + rk_fb_set_prmry_screen_status(SCREEN_UNPREPARE_DDR_CHANGE); + return 0; } static struct rk_lcdc_driver *rk_get_extend_lcdc_drv(void) @@ -3211,6 +3221,7 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id) struct fb_info *pmy_info = NULL; struct rk_lcdc_driver *dev_drv = NULL; struct rk_lcdc_driver *pmy_dev_drv = rk_get_prmry_lcdc_drv(); + struct rk_screen primary_screen; char name[6] = {0}; int i, win_id, load_screen = 0; @@ -3233,19 +3244,37 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id) return -ENODEV; } } + printk("hdmi %s lcdc%d\n", enable ? "connect to" : "remove from", + dev_drv->id); if (enable == 2 /*&& dev_drv->enable*/) return 0; + rk_fb_get_prmry_screen(&primary_screen); if (!enable) { /* if screen type is different, we do not disable lcdc. */ if (dev_drv->cur_screen->type != screen->type) return 0; - for (i = 0; i < dev_drv->lcdc_win_num; i++) { - /* disable the layer which attached to this device */ - if (dev_drv->win[i] && dev_drv->win[i]->state) - dev_drv->ops->open(dev_drv, i, 0); + /* only double lcdc device or hdmi is used as primary + * need to close win + */ + if (rk_fb->disp_mode == DUAL || + primary_screen.type == SCREEN_HDMI) { + for (i = 0; i < dev_drv->lcdc_win_num; i++) { + /* disable the layer which attached to + * this device + */ + if (dev_drv->win[i] && dev_drv->win[i]->state) + dev_drv->ops->open(dev_drv, i, 0); + } + } else { + /* switch lcdc screen to primary screen size + * when hdmi remove if disp mode is ONE DUAL + */ + rk_fb_set_screen_scaler(&primary_screen, 0); + if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable) + dev_drv->trsm_ops->enable(); } hdmi_switch_complete = 0; @@ -3305,8 +3334,10 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id) } hdmi_switch_complete = 1; - if (rk_fb->disp_mode != DUAL) { - if (dev_drv->trsm_ops && dev_drv->trsm_ops->disable) + if (rk_fb->disp_mode != DUAL && + primary_screen.type != SCREEN_HDMI) { + rk_fb_set_screen_scaler(&primary_screen, 1); + if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable) dev_drv->trsm_ops->enable(); } return 0; @@ -3715,6 +3746,7 @@ static int init_lcdc_device_driver(struct rk_fb *rk_fb, dev_drv->cur_screen = screen; /* devie use one lcdc + rk61x scaler for dual display */ if (rk_fb->disp_mode == ONE_DUAL) { + /* struct rk_screen *screen1 = devm_kzalloc(dev_drv->dev, sizeof(struct rk_screen), @@ -3727,6 +3759,7 @@ static int init_lcdc_device_driver(struct rk_fb *rk_fb, screen1->screen_id = 1; screen1->lcdc_id = 1; dev_drv->screen1 = screen1; + */ dev_drv->screen0->sscreen_set = rk_fb_set_screen_scaler; } sprintf(dev_drv->name, "lcdc%d", dev_drv->id); -- 2.34.1