u64 dsp_htotal;
u32 dsp_in_vtotal;
u64 dsp_in_htotal;
- u32 sclk;
+ u64 sclk;
if (!src_screen || !dst_screen)
return 0;
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)
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;
}
* 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);
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)
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;
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;
}
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;
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),
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);