X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=drivers%2Fvideo%2Frockchip%2Flcdc%2Frk3036_lcdc.c;h=dbaf15bfafe4c72448ba72d43f2e2296315629a2;hb=eab94f6acfa516bb9913f68abc6392b3d4abc5eb;hp=8389d5ec98ce6a35a9a13734f5a0647cd616b9a1;hpb=9c37b9f78463f4ba09ee9aa5b75f8418bbaa0c4c;p=firefly-linux-kernel-4.4.55.git diff --git a/drivers/video/rockchip/lcdc/rk3036_lcdc.c b/drivers/video/rockchip/lcdc/rk3036_lcdc.c index 8389d5ec98ce..dbaf15bfafe4 100755 --- a/drivers/video/rockchip/lcdc/rk3036_lcdc.c +++ b/drivers/video/rockchip/lcdc/rk3036_lcdc.c @@ -145,7 +145,7 @@ static int rk3036_lcdc_enable_irq(struct rk_lcdc_driver *dev_drv) lcdc_msk_reg(lcdc_dev, INT_STATUS, mask, val); return 0; } - +/* static int rk3036_lcdc_disable_irq(struct lcdc_device *lcdc_dev) { u32 mask, val; @@ -161,7 +161,7 @@ static int rk3036_lcdc_disable_irq(struct lcdc_device *lcdc_dev) } mdelay(1); return 0; -} +}*/ static void rk_lcdc_read_reg_defalut_cfg(struct lcdc_device *lcdc_dev) @@ -170,7 +170,7 @@ static void rk_lcdc_read_reg_defalut_cfg(struct lcdc_device u32 value = 0; spin_lock(&lcdc_dev->reg_lock); - for (reg = 0; reg < 0xdc; reg += 4) + for (reg = 0; reg < 0xe0; reg += 4) value = lcdc_readl(lcdc_dev, reg); spin_unlock(&lcdc_dev->reg_lock); @@ -180,18 +180,21 @@ static int rk3036_lcdc_alpha_cfg(struct lcdc_device *lcdc_dev) { int win0_top = 0; u32 mask, val; - enum data_format win0_format = lcdc_dev->driver.win[0]->format; - enum data_format win1_format = lcdc_dev->driver.win[1]->format; + enum data_format win0_format = lcdc_dev->driver.win[0]->area[0].format; + enum data_format win1_format = lcdc_dev->driver.win[1]->area[0].format; int win0_alpha_en = ((win0_format == ARGB888) || (win0_format == ABGR888)) ? 1 : 0; int win1_alpha_en = ((win1_format == ARGB888) || (win1_format == ABGR888)) ? 1 : 0; + int atv_layer_cnt = lcdc_dev->driver.win[0]->state + + lcdc_dev->driver.win[1]->state; u32 *_pv = (u32 *)lcdc_dev->regsbak; _pv += (DSP_CTRL0 >> 2); win0_top = ((*_pv) & (m_WIN0_TOP)) >> 8; - if (win0_top && (lcdc_dev->atv_layer_cnt >= 2) && (win0_alpha_en)) { + + if (win0_top && (atv_layer_cnt >= 2) && (win0_alpha_en)) { mask = m_WIN0_ALPHA_EN | m_WIN1_ALPHA_EN | m_WIN1_PREMUL_SCALE; val = v_WIN0_ALPHA_EN(1) | v_WIN1_ALPHA_EN(0) | @@ -203,7 +206,7 @@ static int rk3036_lcdc_alpha_cfg(struct lcdc_device *lcdc_dev) val = v_WIN0_ALPHA_MODE(1) | v_PREMUL_ALPHA_ENABLE(1) | v_ALPHA_MODE_SEL1(0); lcdc_msk_reg(lcdc_dev, DSP_CTRL0, mask, val); - } else if ((!win0_top) && (lcdc_dev->atv_layer_cnt >= 2) && + } else if ((!win0_top) && (atv_layer_cnt >= 2) && (win1_alpha_en)) { mask = m_WIN0_ALPHA_EN | m_WIN1_ALPHA_EN | m_WIN1_PREMUL_SCALE; @@ -221,6 +224,21 @@ static int rk3036_lcdc_alpha_cfg(struct lcdc_device *lcdc_dev) val = v_WIN0_ALPHA_EN(0) | v_WIN1_ALPHA_EN(0); lcdc_msk_reg(lcdc_dev, ALPHA_CTRL, mask, val); } + + if (lcdc_dev->driver.win[2]->state == 1) { + mask = m_HWC_ALPAH_EN; + val = v_HWC_ALPAH_EN(1); + lcdc_msk_reg(lcdc_dev, ALPHA_CTRL, mask, val); + + mask = m_HWC_ALPHA_MODE; + val = v_HWC_ALPHA_MODE(1); + lcdc_msk_reg(lcdc_dev, DSP_CTRL0, mask, val); + } else { + mask = m_HWC_ALPAH_EN; + val = v_HWC_ALPAH_EN(0); + lcdc_msk_reg(lcdc_dev, ALPHA_CTRL, mask, val); + } + return 0; } @@ -228,16 +246,15 @@ static void lcdc_layer_update_regs(struct lcdc_device *lcdc_dev, struct rk_lcdc_win *win) { u32 mask, val; + int hwc_size; if (win->state == 1) { if (win->id == 0) { mask = m_WIN0_EN | m_WIN0_FORMAT | m_WIN0_RB_SWAP; val = v_WIN0_EN(win->state) | - v_WIN0_FORMAT(win->fmt_cfg) | - v_WIN0_RB_SWAP(win->swap_rb); + v_WIN0_FORMAT(win->area[0].fmt_cfg) | + v_WIN0_RB_SWAP(win->area[0].swap_rb); lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val); - lcdc_msk_reg(lcdc_dev, DSP_CTRL0, m_WIN0_INTERLACE_EN, - v_WIN0_INTERLACE_EN(win->interlace_read)); lcdc_writel(lcdc_dev, WIN0_SCL_FACTOR_YRGB, v_X_SCL_FACTOR(win->scale_yrgb_x) | v_Y_SCL_FACTOR(win->scale_yrgb_y)); @@ -265,11 +282,9 @@ static void lcdc_layer_update_regs(struct lcdc_device *lcdc_dev, } else if (win->id == 1) { mask = m_WIN1_EN | m_WIN1_FORMAT | m_WIN1_RB_SWAP; val = v_WIN1_EN(win->state) | - v_WIN1_FORMAT(win->fmt_cfg) | - v_WIN1_RB_SWAP(win->swap_rb); + v_WIN1_FORMAT(win->area[0].fmt_cfg) | + v_WIN1_RB_SWAP(win->area[0].swap_rb); lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val); - lcdc_msk_reg(lcdc_dev, DSP_CTRL0, m_WIN1_INTERLACE_EN, - v_WIN1_INTERLACE_EN(win->interlace_read)); lcdc_writel(lcdc_dev, WIN1_SCL_FACTOR_YRGB, v_X_SCL_FACTOR(win->scale_yrgb_x) | v_Y_SCL_FACTOR(win->scale_yrgb_y)); @@ -286,20 +301,46 @@ static void lcdc_layer_update_regs(struct lcdc_device *lcdc_dev, v_DSP_STX(win->area[0].dsp_stx) | v_DSP_STY(win->area[0].dsp_sty)); lcdc_writel(lcdc_dev, WIN1_MST, win->area[0].y_addr); - } /* else if (win->id == 2) { - }*/ + } else if (win->id == 2) { + mask = m_HWC_EN | m_HWC_LODAD_EN; + val = v_HWC_EN(win->state) | v_HWC_LODAD_EN(1); + lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val); + if ((win->area[0].xsize == 32) && + (win->area[0].ysize == 32)) + hwc_size = 0; + else if ((win->area[0].xsize == 64) && + (win->area[0].ysize == 64)) + hwc_size = 1; + else + dev_err(lcdc_dev->dev, + "unsupport hwc size:x=%d,y=%d\n", + win->area[0].xsize, + win->area[0].ysize); + lcdc_writel(lcdc_dev, HWC_DSP_ST, + v_DSP_STX(win->area[0].dsp_stx) | + v_DSP_STY(win->area[0].dsp_sty)); + lcdc_writel(lcdc_dev, HWC_MST, win->area[0].y_addr); + } } else { win->area[0].y_addr = 0; win->area[0].uv_addr = 0; - if (win->id == 0) + if (win->id == 0) { lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_WIN0_EN, v_WIN0_EN(0)); - else if (win->id == 1) + lcdc_writel(lcdc_dev, WIN0_YRGB_MST, + win->area[0].y_addr); + lcdc_writel(lcdc_dev, WIN0_CBR_MST, + win->area[0].uv_addr); + } else if (win->id == 1) { lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_WIN1_EN, v_WIN1_EN(0)); - else if (win->id == 2) + lcdc_writel(lcdc_dev, WIN1_MST, win->area[0].y_addr); + } else if (win->id == 2) { lcdc_msk_reg(lcdc_dev, - SYS_CTRL, m_HWC_EN, v_HWC_EN(0)); + SYS_CTRL, m_HWC_EN | m_HWC_LODAD_EN, + v_HWC_EN(0) | v_HWC_LODAD_EN(0)); + lcdc_writel(lcdc_dev, HWC_MST, win->area[0].y_addr); + } } rk3036_lcdc_alpha_cfg(lcdc_dev); } @@ -316,9 +357,9 @@ static void lcdc_layer_enable(struct lcdc_device *lcdc_dev, "wakeup from standby!\n"); lcdc_dev->standby = 0; } - lcdc_dev->atv_layer_cnt++; - } else if ((lcdc_dev->atv_layer_cnt > 0) && (!open)) { - lcdc_dev->atv_layer_cnt--; + lcdc_dev->atv_layer_cnt |= (1 << win_id); + } else if ((lcdc_dev->atv_layer_cnt & (1 << win_id)) && (!open)) { + lcdc_dev->atv_layer_cnt &= ~(1 << win_id); } lcdc_dev->driver.win[win_id]->state = open; if (!open) { @@ -335,7 +376,7 @@ static void lcdc_layer_enable(struct lcdc_device *lcdc_dev, } spin_unlock(&lcdc_dev->reg_lock); } - +/* static int rk3036_lcdc_reg_update(struct rk_lcdc_driver *dev_drv) { struct lcdc_device *lcdc_dev = @@ -355,7 +396,6 @@ static int rk3036_lcdc_reg_update(struct rk_lcdc_driver *dev_drv) lcdc_cfg_done(lcdc_dev); } spin_unlock(&lcdc_dev->reg_lock); - /* if (dev_drv->wait_fs) { */ if (0) { spin_lock_irqsave(&dev_drv->cpl_lock, flags); init_completion(&dev_drv->frame_done); @@ -373,10 +413,10 @@ static int rk3036_lcdc_reg_update(struct rk_lcdc_driver *dev_drv) DBG(2, "%s for lcdc%d\n", __func__, lcdc_dev->id); return 0; } - +*/ static void rk3036_lcdc_reg_restore(struct lcdc_device *lcdc_dev) { - memcpy((u8 *)lcdc_dev->regs, (u8 *)lcdc_dev->regsbak, 0xdc); + memcpy((u8 *)lcdc_dev->regs, (u8 *)lcdc_dev->regsbak, 0xe0); } static void rk3036_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv) @@ -385,7 +425,7 @@ static void rk3036_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv) struct lcdc_device *lcdc_dev = container_of(dev_drv, struct lcdc_device, driver); - spin_lock(&lcdc_dev->reg_lock); + /*spin_lock(&lcdc_dev->reg_lock);*/ if (likely(lcdc_dev->clk_on)) { mask = m_MMU_EN | m_AXI_MAX_OUTSTANDING_EN | m_AXI_OUTSTANDING_MAX_NUM; @@ -393,9 +433,40 @@ static void rk3036_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv) v_AXI_MAX_OUTSTANDING_EN(1); lcdc_msk_reg(lcdc_dev, AXI_BUS_CTRL, mask, val); } + /*spin_unlock(&lcdc_dev->reg_lock);*/ +} + +static int rk3036_lcdc_set_hwc_lut(struct rk_lcdc_driver *dev_drv, + int *hwc_lut, int mode) +{ + int i = 0; + int __iomem *c; + int v; + int len = 256*4; + + struct lcdc_device *lcdc_dev = + container_of(dev_drv, struct lcdc_device, driver); + if (dev_drv->hwc_lut == NULL) + dev_drv->hwc_lut = devm_kzalloc(lcdc_dev->dev, len, GFP_KERNEL); + + spin_lock(&lcdc_dev->reg_lock); + lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_HWC_LUT_EN, v_HWC_LUT_EN(0)); + lcdc_cfg_done(lcdc_dev); + mdelay(25); + for (i = 0; i < 256; i++) { + if (mode == 1) + dev_drv->hwc_lut[i] = hwc_lut[i]; + v = dev_drv->hwc_lut[i]; + c = lcdc_dev->hwc_lut_addr_base + i; + writel_relaxed(v, c); + } + lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_HWC_LUT_EN, v_HWC_LUT_EN(1)); + lcdc_cfg_done(lcdc_dev); spin_unlock(&lcdc_dev->reg_lock); + return 0; } +#if 0 static int rk3036_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv) { #ifdef CONFIG_RK_FPGA @@ -420,7 +491,7 @@ static int rk3036_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv) lcdc_dev->driver.name, clk_get_rate(lcdc_dev->dclk), fps); return 0; } - +#endif /********do basic init*********/ static int rk3036_lcdc_pre_init(struct rk_lcdc_driver *dev_drv) { @@ -445,6 +516,9 @@ static int rk3036_lcdc_pre_init(struct rk_lcdc_driver *dev_drv) /*backup reg config at uboot*/ rk_lcdc_read_reg_defalut_cfg(lcdc_dev); + if (lcdc_readl(lcdc_dev, AXI_BUS_CTRL) & m_TVE_DAC_DCLK_EN) + dev_drv->cur_screen->type = SCREEN_TVOUT; + lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_AUTO_GATING_EN, v_AUTO_GATING_EN(0)); lcdc_cfg_done(lcdc_dev); @@ -552,7 +626,7 @@ static int rk3036_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen) v_HASP(screen->mode.hsync_len + left_margin); lcdc_writel(lcdc_dev, DSP_HACT_ST_END, val); - if (screen->mode.vmode == FB_VMODE_INTERLACED) { + if (screen->mode.vmode & FB_VMODE_INTERLACED) { /*First Field Timing*/ lcdc_writel(lcdc_dev, DSP_VTOTAL_VS_END, v_VSYNC(screen->mode.vsync_len) | @@ -585,12 +659,16 @@ static int rk3036_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen) m_INTERLACE_DSP_POL | m_WIN1_DIFF_DCLK_EN | m_WIN0_YRGB_DEFLICK_EN | - m_WIN0_CBR_DEFLICK_EN, + m_WIN0_CBR_DEFLICK_EN | + m_WIN0_INTERLACE_EN | + m_WIN1_INTERLACE_EN, v_INTERLACE_DSP_EN(1) | v_INTERLACE_DSP_POL(0) | v_WIN1_DIFF_DCLK_EN(1) | v_WIN0_YRGB_DEFLICK_EN(1) | - v_WIN0_CBR_DEFLICK_EN(1)); + v_WIN0_CBR_DEFLICK_EN(1) | + v_WIN0_INTERLACE_EN(1) | + v_WIN1_INTERLACE_EN(1)); } else { val = v_VSYNC(screen->mode.vsync_len) | v_VERPRD(screen->mode.vsync_len + upper_margin + @@ -607,11 +685,15 @@ static int rk3036_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen) m_INTERLACE_DSP_EN | m_WIN1_DIFF_DCLK_EN | m_WIN0_YRGB_DEFLICK_EN | - m_WIN0_CBR_DEFLICK_EN, + m_WIN0_CBR_DEFLICK_EN | + m_WIN0_INTERLACE_EN | + m_WIN1_INTERLACE_EN, v_INTERLACE_DSP_EN(0) | v_WIN1_DIFF_DCLK_EN(0) | v_WIN0_YRGB_DEFLICK_EN(0) | - v_WIN0_CBR_DEFLICK_EN(0)); + v_WIN0_CBR_DEFLICK_EN(0) | + v_WIN0_INTERLACE_EN(1) | + v_WIN1_INTERLACE_EN(1)); } } spin_unlock(&lcdc_dev->reg_lock); @@ -646,7 +728,6 @@ static int rk3036_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id, if ((open) && (!lcdc_dev->atv_layer_cnt)) { rk3036_lcdc_pre_init(dev_drv); rk3036_lcdc_clk_enable(lcdc_dev); - #if defined(CONFIG_ROCKCHIP_IOMMU) if (dev_drv->iommu_enabled) { if (!dev_drv->mmu_dev) { dev_drv->mmu_dev = @@ -654,8 +735,7 @@ static int rk3036_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id, dev_drv->mmu_dts_name); if (dev_drv->mmu_dev) { rk_fb_platform_set_sysmmu(dev_drv->mmu_dev, - dev_drv->dev); - rockchip_iovmm_activate(dev_drv->dev); + dev_drv->dev); } else { dev_err(dev_drv->dev, "failed to get iommu device\n" @@ -664,12 +744,11 @@ static int rk3036_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id, } } } - #endif rk3036_lcdc_reg_restore(lcdc_dev); - if (dev_drv->iommu_enabled) - rk3036_lcdc_mmu_en(dev_drv); + /*if (dev_drv->iommu_enabled) + rk3036_lcdc_mmu_en(dev_drv);*/ if ((support_uboot_display() && (lcdc_dev->prop == PRMRY))) { - rk3036_lcdc_set_dclk(dev_drv); + /*rk3036_lcdc_set_dclk(dev_drv);*/ rk3036_lcdc_enable_irq(dev_drv); } else { rk3036_load_screen(dev_drv, 1); @@ -682,18 +761,17 @@ static int rk3036_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id, dev_err(lcdc_dev->dev, "invalid win id:%d\n", win_id); /*when all layer closed,disable clk */ +/* if ((!open) && (!lcdc_dev->atv_layer_cnt)) { rk3036_lcdc_disable_irq(lcdc_dev); rk3036_lcdc_reg_update(dev_drv); - #if defined(CONFIG_ROCKCHIP_IOMMU) if (dev_drv->iommu_enabled) { if (dev_drv->mmu_dev) rockchip_iovmm_deactivate(dev_drv->dev); } - #endif rk3036_lcdc_clk_disable(lcdc_dev); } - +*/ return 0; } @@ -714,6 +792,8 @@ static int rk3036_lcdc_set_par(struct rk_lcdc_driver *dev_drv, int win_id) win = dev_drv->win[0]; } else if (win_id == 1) { win = dev_drv->win[1]; + } else if (win_id == 2) { + win = dev_drv->win[2]; } else { dev_err(dev_drv->dev, "un supported win number:%d\n", win_id); return -EINVAL; @@ -737,7 +817,7 @@ static int rk3036_lcdc_set_par(struct rk_lcdc_driver *dev_drv, int win_id) win->area[0].dsp_stx = win->post_cfg.xpos + screen->mode.left_margin + screen->mode.hsync_len; - if (screen->mode.vmode == FB_VMODE_INTERLACED) { + if (screen->mode.vmode & FB_VMODE_INTERLACED) { win->post_cfg.ysize /= 2; win->area[0].dsp_sty = win->post_cfg.ypos/2 + screen->mode.upper_margin + @@ -749,41 +829,36 @@ static int rk3036_lcdc_set_par(struct rk_lcdc_driver *dev_drv, int win_id) } win->scale_yrgb_x = calscale(win->area[0].xact, win->post_cfg.xsize); win->scale_yrgb_y = calscale(win->area[0].yact, win->post_cfg.ysize); - win->interlace_read = 0; - if((screen->mode.xres == 720) && - ((screen->mode.yres == 576) || (screen->mode.yres == 480))) { - if(win->scale_yrgb_y > 2*0x1000) - win->interlace_read = 1; - } - switch (win->format) { + + switch (win->area[0].format) { case ARGB888: - win->fmt_cfg = VOP_FORMAT_ARGB888; - win->swap_rb = 0; + win->area[0].fmt_cfg = VOP_FORMAT_ARGB888; + win->area[0].swap_rb = 0; break; case XBGR888: - win->fmt_cfg = VOP_FORMAT_ARGB888; - win->swap_rb = 1; + win->area[0].fmt_cfg = VOP_FORMAT_ARGB888; + win->area[0].swap_rb = 1; break; case ABGR888: - win->fmt_cfg = VOP_FORMAT_ARGB888; - win->swap_rb = 1; + win->area[0].fmt_cfg = VOP_FORMAT_ARGB888; + win->area[0].swap_rb = 1; break; case RGB888: - win->fmt_cfg = VOP_FORMAT_RGB888; - win->swap_rb = 0; + win->area[0].fmt_cfg = VOP_FORMAT_RGB888; + win->area[0].swap_rb = 0; break; case RGB565: - win->fmt_cfg = VOP_FORMAT_RGB565; - win->swap_rb = 0; + win->area[0].fmt_cfg = VOP_FORMAT_RGB565; + win->area[0].swap_rb = 0; break; case YUV444: if (win_id == 0) { - win->fmt_cfg = VOP_FORMAT_YCBCR444; + win->area[0].fmt_cfg = VOP_FORMAT_YCBCR444; win->scale_cbcr_x = calscale(win->area[0].xact, win->post_cfg.xsize); win->scale_cbcr_y = calscale(win->area[0].yact, win->post_cfg.ysize); - win->swap_rb = 0; + win->area[0].swap_rb = 0; } else { dev_err(lcdc_dev->driver.dev, "%s:un supported format!\n", @@ -792,12 +867,12 @@ static int rk3036_lcdc_set_par(struct rk_lcdc_driver *dev_drv, int win_id) break; case YUV422: if (win_id == 0) { - win->fmt_cfg = VOP_FORMAT_YCBCR422; + win->area[0].fmt_cfg = VOP_FORMAT_YCBCR422; win->scale_cbcr_x = calscale((win->area[0].xact / 2), win->post_cfg.xsize); win->scale_cbcr_y = calscale(win->area[0].yact, win->post_cfg.ysize); - win->swap_rb = 0; + win->area[0].swap_rb = 0; } else { dev_err(lcdc_dev->driver.dev, "%s:un supported format!\n", @@ -806,12 +881,12 @@ static int rk3036_lcdc_set_par(struct rk_lcdc_driver *dev_drv, int win_id) break; case YUV420: if (win_id == 0) { - win->fmt_cfg = VOP_FORMAT_YCBCR420; + win->area[0].fmt_cfg = VOP_FORMAT_YCBCR420; win->scale_cbcr_x = calscale(win->area[0].xact / 2, win->post_cfg.xsize); win->scale_cbcr_y = calscale(win->area[0].yact / 2, win->post_cfg.ysize); - win->swap_rb = 0; + win->area[0].swap_rb = 0; } else { dev_err(lcdc_dev->driver.dev, "%s:un supported format!\n", @@ -828,7 +903,7 @@ static int rk3036_lcdc_set_par(struct rk_lcdc_driver *dev_drv, int win_id) DBG(2, "lcdc%d>>%s\n" ">>format:%s>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d\n" ">>xvir:%d>>yvir:%d>>xpos:%d>>ypos:%d>>\n", lcdc_dev->id, - __func__, get_format_string(win->format, fmt), + __func__, get_format_string(win->area[0].format, fmt), win->area[0].xact, win->area[0].yact, win->post_cfg.xsize, win->post_cfg.ysize, win->area[0].xvir, win->area[0].yvir, win->post_cfg.xpos, win->post_cfg.ypos); @@ -851,6 +926,8 @@ static int rk3036_lcdc_pan_display(struct rk_lcdc_driver *dev_drv, int win_id) win = dev_drv->win[0]; } else if (win_id == 1) { win = dev_drv->win[1]; + } else if (win_id == 2) { + win = dev_drv->win[2]; } else { dev_err(dev_drv->dev, "invalid win number:%d!\n", win_id); return -EINVAL; @@ -930,7 +1007,8 @@ static int rk3036_lcdc_get_win_id(struct rk_lcdc_driver *dev_drv, } static int rk3036_lcdc_get_win_state(struct rk_lcdc_driver *dev_drv, - int win_id) + int win_id, + int area_id) { return dev_drv->win[win_id]->state; } @@ -940,13 +1018,25 @@ static int rk3036_lcdc_ovl_mgr(struct rk_lcdc_driver *dev_drv, int swap, { struct lcdc_device *lcdc_dev = container_of(dev_drv, struct lcdc_device, driver); - int ovl; - + struct rk_lcdc_win *win0 = lcdc_dev->driver.win[0]; + struct rk_lcdc_win *win1 = lcdc_dev->driver.win[1]; + int ovl, needswap = 0; + + if (!swap) { + if (win0->z_order >= 0 && + win1->z_order >= 0 && + win0->z_order > win1->z_order) + needswap = 1; + else + needswap = 0; + } else { + needswap = swap; + } spin_lock(&lcdc_dev->reg_lock); if (lcdc_dev->clk_on) { if (set) { lcdc_msk_reg(lcdc_dev, DSP_CTRL0, m_WIN0_TOP, - v_WIN0_TOP(swap)); + v_WIN0_TOP(needswap)); ovl = swap; } else { ovl = lcdc_read_bit(lcdc_dev, DSP_CTRL0, m_WIN0_TOP); @@ -1008,6 +1098,8 @@ static int rk3036_lcdc_early_resume(struct rk_lcdc_driver *dev_drv) if (lcdc_dev->atv_layer_cnt) { rk3036_lcdc_clk_enable(lcdc_dev); rk3036_lcdc_reg_restore(lcdc_dev); + /*set hwc lut*/ + rk3036_lcdc_set_hwc_lut(dev_drv, dev_drv->hwc_lut, 0); spin_lock(&lcdc_dev->reg_lock); @@ -1053,13 +1145,38 @@ static int rk3036_lcdc_blank(struct rk_lcdc_driver *dev_drv, static int rk3036_lcdc_cfg_done(struct rk_lcdc_driver *dev_drv) { - struct lcdc_device *lcdc_dev = container_of(dev_drv, - struct lcdc_device, driver); + struct lcdc_device *lcdc_dev = + container_of(dev_drv, struct lcdc_device, driver); + int i; + struct rk_lcdc_win *win = NULL; spin_lock(&lcdc_dev->reg_lock); if (lcdc_dev->clk_on) { + if (dev_drv->iommu_enabled) { + if (!lcdc_dev->iommu_status && dev_drv->mmu_dev) { + lcdc_dev->iommu_status = 1; + if (support_uboot_display() && + lcdc_dev->prop == PRMRY) { + lcdc_msk_reg(lcdc_dev, SYS_CTRL, + m_WIN0_EN, + v_WIN0_EN(0)); + } + lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_LCDC_STANDBY, + v_LCDC_STANDBY(1)); + lcdc_cfg_done(lcdc_dev); + mdelay(50); + rockchip_iovmm_activate(dev_drv->dev); + rk3036_lcdc_mmu_en(dev_drv); + } + } lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_LCDC_STANDBY, v_LCDC_STANDBY(lcdc_dev->standby)); + for (i = 0; i < ARRAY_SIZE(lcdc_win); i++) { + win = dev_drv->win[i]; + if ((win->state == 0) && (win->last_state == 1)) + lcdc_layer_update_regs(lcdc_dev, win); + win->last_state = win->state; + } lcdc_cfg_done(lcdc_dev); } spin_unlock(&lcdc_dev->reg_lock); @@ -1238,15 +1355,29 @@ static int rk3036_lcdc_set_overscan(struct rk_lcdc_driver *dev_drv, return 0; } -static int rk3036_fb_win_remap(struct rk_lcdc_driver *dev_drv, - enum fb_win_map_order order) +static int rk3036_fb_win_remap(struct rk_lcdc_driver *dev_drv, u16 order) { + struct rk_lcdc_win_area area; + int fb2_win_id, fb1_win_id, fb0_win_id; + mutex_lock(&dev_drv->fb_win_id_mutex); if (order == FB_DEFAULT_ORDER) - order = FB0_WIN1_FB1_WIN0_FB2_WIN2; - dev_drv->fb2_win_id = order / 100; - dev_drv->fb1_win_id = (order / 10) % 10; - dev_drv->fb0_win_id = order % 10; + order = FB0_WIN0_FB1_WIN1_FB2_WIN2; + + fb2_win_id = order / 100; + fb1_win_id = (order / 10) % 10; + fb0_win_id = order % 10; + + if (fb0_win_id != dev_drv->fb0_win_id) { + area = dev_drv->win[(int)dev_drv->fb0_win_id]->area[0]; + dev_drv->win[(int)dev_drv->fb0_win_id]->area[0] = + dev_drv->win[fb0_win_id]->area[0]; + dev_drv->win[fb0_win_id]->area[0] = area; + dev_drv->fb0_win_id = fb0_win_id; + } + dev_drv->fb1_win_id = fb1_win_id; + dev_drv->fb2_win_id = fb2_win_id; + mutex_unlock(&dev_drv->fb_win_id_mutex); return 0; @@ -1314,14 +1445,14 @@ static int rk3036_lcdc_poll_vblank(struct rk_lcdc_driver *dev_drv) } static int rk3036_lcdc_get_dsp_addr(struct rk_lcdc_driver *dev_drv, - unsigned int *dsp_addr) + unsigned int dsp_addr[][4]) { struct lcdc_device *lcdc_dev = container_of(dev_drv, struct lcdc_device, driver); if (lcdc_dev->clk_on) { - dsp_addr[0] = lcdc_readl(lcdc_dev, WIN0_YRGB_MST); - dsp_addr[1] = lcdc_readl(lcdc_dev, WIN1_MST); + dsp_addr[0][0] = lcdc_readl(lcdc_dev, WIN0_YRGB_MST); + dsp_addr[1][0] = lcdc_readl(lcdc_dev, WIN1_MST); } return 0; } @@ -1341,7 +1472,7 @@ static ssize_t rk3036_lcdc_get_disp_info(struct rk_lcdc_driver *dev_drv, } size = snprintf(buf, PAGE_SIZE, "win%d: %s\n", win_id, - get_format_string(win->format, fmt)); + get_format_string(win->area[0].format, fmt)); size += snprintf(buf + size, PAGE_SIZE - size, " xact %d yact %d xvir %d yvir %d\n", win->area[0].xact, win->area[0].yact, @@ -1406,11 +1537,11 @@ static struct rk_lcdc_drv_ops lcdc_drv_ops = { .get_dsp_bcsh_bcs = rk3036_lcdc_get_bcsh_bcs, .open_bcsh = rk3036_lcdc_open_bcsh, .set_overscan = rk3036_lcdc_set_overscan, + .set_hwc_lut = rk3036_lcdc_set_hwc_lut, }; static int rk3036_lcdc_parse_dt(struct lcdc_device *lcdc_dev) { -#if defined(CONFIG_ROCKCHIP_IOMMU) struct device_node *np = lcdc_dev->dev->of_node; int val; @@ -1418,9 +1549,11 @@ static int rk3036_lcdc_parse_dt(struct lcdc_device *lcdc_dev) lcdc_dev->driver.iommu_enabled = 0; else lcdc_dev->driver.iommu_enabled = val; -#else - lcdc_dev->driver.iommu_enabled = 0; -#endif + if (of_property_read_u32(np, "rockchip,fb-win-map", &val)) + lcdc_dev->driver.fb_win_map = FB_DEFAULT_ORDER; + else + lcdc_dev->driver.fb_win_map = val; + return 0; } @@ -1453,6 +1586,8 @@ static int rk3036_lcdc_probe(struct platform_device *pdev) if (IS_ERR(lcdc_dev->regsbak)) return PTR_ERR(lcdc_dev->regsbak); + lcdc_dev->hwc_lut_addr_base = (lcdc_dev->regs + HWC_LUT_ADDR); + lcdc_dev->prop = PRMRY; dev_set_name(lcdc_dev->dev, "lcdc%d", lcdc_dev->id); dev_drv = &lcdc_dev->driver; dev_drv->dev = dev; @@ -1550,4 +1685,4 @@ static void __exit rk3036_lcdc_module_exit(void) } fs_initcall(rk3036_lcdc_module_init); -module_exit(rk3036_lcdc_module_exit); \ No newline at end of file +module_exit(rk3036_lcdc_module_exit);