From 9e5568c68a5d19ebccd3a8a4032a34e480deda48 Mon Sep 17 00:00:00 2001 From: hjc Date: Wed, 3 Sep 2014 18:15:13 +0800 Subject: [PATCH] rk312x lcdc: add support hwc layer --- arch/arm/boot/dts/rk312x.dtsi | 2 +- drivers/video/rockchip/lcdc/rk312x_lcdc.c | 71 ++++++++++++++++++++++- drivers/video/rockchip/lcdc/rk312x_lcdc.h | 3 +- drivers/video/rockchip/rkfb_sysfs.c | 47 +++++++++++++++ include/linux/rk_fb.h | 2 + 5 files changed, 120 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/rk312x.dtsi b/arch/arm/boot/dts/rk312x.dtsi index f75c674f031a..a686571d741a 100755 --- a/arch/arm/boot/dts/rk312x.dtsi +++ b/arch/arm/boot/dts/rk312x.dtsi @@ -704,7 +704,7 @@ lcdc: lcdc@1010e000 { compatible = "rockchip,rk312x-lcdc"; rockchip,prop = ; - reg = <0x1010e000 0x0300>; + reg = <0x1010e000 0x1000>; interrupts = ; clocks = <&clk_gates6 0>, <&dclk_lcdc0>, <&clk_gates6 1>, <&sclk_lcdc0>, <&pd_vop>, <&clk_cpll>; clock-names = "aclk_lcdc", "dclk_lcdc", "hclk_lcdc", "sclk_lcdc", "pd_lcdc", "sclk_pll"; diff --git a/drivers/video/rockchip/lcdc/rk312x_lcdc.c b/drivers/video/rockchip/lcdc/rk312x_lcdc.c index 349238e93b2f..859ee934d0fd 100755 --- a/drivers/video/rockchip/lcdc/rk312x_lcdc.c +++ b/drivers/video/rockchip/lcdc/rk312x_lcdc.c @@ -255,6 +255,20 @@ static int rk312x_lcdc_alpha_cfg(struct lcdc_device *lcdc_dev) 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; } @@ -307,6 +321,7 @@ 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 (lcdc_dev->soc_type == VOP_RK312X) @@ -380,6 +395,21 @@ static void lcdc_layer_update_regs(struct lcdc_device *lcdc_dev, } else if (win->id == 2) { + mask = m_HWC_EN; + val = v_HWC_EN(win->state); + 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; @@ -488,7 +518,34 @@ static void rk312x_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv) } spin_unlock(&lcdc_dev->reg_lock); } +static int rk312x_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<<2; + 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; +} static int rk312x_lcdc_set_lut(struct rk_lcdc_driver *dev_drv) { int i = 0; @@ -503,7 +560,7 @@ static int rk312x_lcdc_set_lut(struct rk_lcdc_driver *dev_drv) mdelay(25); for (i = 0; i < 256; i++) { v = dev_drv->cur_screen->dsp_lut[i]; - c = lcdc_dev->dsp_lut_addr_base + i; + c = lcdc_dev->dsp_lut_addr_base + i<<2; writel_relaxed(v, c); } @@ -1198,6 +1255,8 @@ static int rk312x_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; @@ -1312,7 +1371,9 @@ static int rk312x_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 { + } 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; } @@ -1473,6 +1534,8 @@ static int rk312x_lcdc_early_resume(struct rk_lcdc_driver *dev_drv) /* set screen lut */ if (dev_drv->cur_screen->dsp_lut) rk312x_lcdc_set_lut(dev_drv); + /*set hwc lut*/ + rk312x_lcdc_set_hwc_lut(dev_drv, dev_drv->hwc_lut, 0); spin_lock(&lcdc_dev->reg_lock); @@ -2033,6 +2096,7 @@ static struct rk_lcdc_drv_ops lcdc_drv_ops = { .get_dsp_bcsh_bcs = rk312x_lcdc_get_bcsh_bcs, .open_bcsh = rk312x_lcdc_open_bcsh, .set_screen_scaler = rk312x_lcdc_set_scaler, + .set_hwc_lut = rk312x_lcdc_set_hwc_lut, }; #if 0 static const struct rk_lcdc_drvdata rk3036_lcdc_drvdata = { @@ -2125,7 +2189,8 @@ static int rk312x_lcdc_probe(struct platform_device *pdev) ret = PTR_ERR(lcdc_dev->regsbak); goto err_remap_reg; } - + lcdc_dev->hwc_lut_addr_base = (lcdc_dev->regs + HWC_LUT_ADDR); + lcdc_dev->dsp_lut_addr_base = (lcdc_dev->regs + DSP_LUT_ADDR); dev_set_name(lcdc_dev->dev, "lcdc%d", lcdc_dev->id); dev_drv = &lcdc_dev->driver; dev_drv->dev = dev; diff --git a/drivers/video/rockchip/lcdc/rk312x_lcdc.h b/drivers/video/rockchip/lcdc/rk312x_lcdc.h index 8bd3226d88cc..202b267d8f65 100755 --- a/drivers/video/rockchip/lcdc/rk312x_lcdc.h +++ b/drivers/video/rockchip/lcdc/rk312x_lcdc.h @@ -667,7 +667,8 @@ struct lcdc_device { u32 reg_phy_base; /* physical basic address of lcdc register */ u32 len; /* physical map length of lcdc register */ spinlock_t reg_lock; /* one time only one process allowed to config the register */ - + + int __iomem *hwc_lut_addr_base; int __iomem *dsp_lut_addr_base; int prop; /* used for primary or extended display device */ diff --git a/drivers/video/rockchip/rkfb_sysfs.c b/drivers/video/rockchip/rkfb_sysfs.c index b69e388027d4..5c048f57ee0c 100755 --- a/drivers/video/rockchip/rkfb_sysfs.c +++ b/drivers/video/rockchip/rkfb_sysfs.c @@ -247,6 +247,52 @@ static ssize_t set_fb_win_map(struct device *dev, struct device_attribute *attr, return count; } +static ssize_t show_hwc_lut(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return 0; +} + +static ssize_t set_hwc_lut(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int hwc_lut[256]; + const char *start = buf; + int i = 256, temp; + int space_max = 10; + + struct fb_info *fbi = dev_get_drvdata(dev); + struct rk_lcdc_driver *dev_drv = + (struct rk_lcdc_driver *)fbi->par; + + /*printk("count:%d\n>>%s\n\n",count,start);*/ + for (i = 0; i < 256; i++) { + space_max = 10; /*max space number 10*/ + temp = simple_strtoul(start, NULL, 10); + hwc_lut[i] = temp; + do { + start++; + space_max--; + } while ((*start != ' ') && space_max); + + if (!space_max) + break; + else + start++; + } +#if 0 + for (i = 0; i < 16; i++) { + for (j = 0; j < 16; j++) + printk("0x%08x ", hwc_lut[i * 16 + j]); + printk("\n"); + } +#endif + if(dev_drv->ops->set_hwc_lut) + dev_drv->ops->set_hwc_lut(dev_drv, hwc_lut, 1); + + return count; +} + static ssize_t show_dsp_lut(struct device *dev, struct device_attribute *attr, char *buf) { @@ -525,6 +571,7 @@ static struct device_attribute rkfb_attrs[] = { __ATTR(fps, S_IRUGO | S_IWUSR, show_fps, set_fps), __ATTR(map, S_IRUGO | S_IWUSR, show_fb_win_map, set_fb_win_map), __ATTR(dsp_lut, S_IRUGO | S_IWUSR, show_dsp_lut, set_dsp_lut), + __ATTR(hwc_lut, S_IRUGO | S_IWUSR, show_hwc_lut, set_hwc_lut), __ATTR(cabc, S_IRUGO | S_IWUSR, show_dsp_cabc, set_dsp_cabc), __ATTR(bcsh, S_IRUGO | S_IWUSR, show_dsp_bcsh, set_dsp_bcsh), __ATTR(scale, S_IRUGO | S_IWUSR, show_scale, set_scale), diff --git a/include/linux/rk_fb.h b/include/linux/rk_fb.h index be9762f6bb81..f4a1c3785033 100755 --- a/include/linux/rk_fb.h +++ b/include/linux/rk_fb.h @@ -418,6 +418,7 @@ struct rk_lcdc_drv_ops { int (*fb_win_remap) (struct rk_lcdc_driver *dev_drv, u16 fb_win_map_order); int (*set_dsp_lut) (struct rk_lcdc_driver *dev_drv, int *lut); + int (*set_hwc_lut) (struct rk_lcdc_driver *dev_drv, int *hwc_lut, int mode); int (*read_dsp_lut) (struct rk_lcdc_driver *dev_drv, int *lut); int (*lcdc_hdmi_process) (struct rk_lcdc_driver *dev_drv, int mode); /*some lcdc need to some process in hdmi mode*/ int (*set_irq_to_cpu)(struct rk_lcdc_driver *dev_drv,int enable); @@ -589,6 +590,7 @@ struct rk_lcdc_driver { #endif struct overscan overscan; struct rk_lcdc_bcsh bcsh; + int *hwc_lut; }; /*disp_mode: dual display mode -- 2.34.1