rk312x lcdc: add support hwc layer
authorhjc <hjc@rock-chips.com>
Wed, 3 Sep 2014 10:15:13 +0000 (18:15 +0800)
committerhjc <hjc@rock-chips.com>
Wed, 3 Sep 2014 11:07:15 +0000 (19:07 +0800)
arch/arm/boot/dts/rk312x.dtsi
drivers/video/rockchip/lcdc/rk312x_lcdc.c
drivers/video/rockchip/lcdc/rk312x_lcdc.h
drivers/video/rockchip/rkfb_sysfs.c
include/linux/rk_fb.h

index f75c674f031a1b8ab6216f2621f4a64089e4ac59..a686571d741af4ffe55a7af85608c4ae7b21f6c4 100755 (executable)
        lcdc: lcdc@1010e000 {
                compatible = "rockchip,rk312x-lcdc";
                rockchip,prop = <PRMRY>;
-               reg = <0x1010e000 0x0300>;
+               reg = <0x1010e000 0x1000>;
                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
                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";
index 349238e93b2fabd4f34f4955205aa485f5a7aef9..859ee934d0fd61e3f5e3ce54c1a2174b285e8758 100755 (executable)
@@ -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;
index 8bd3226d88cc4038c999a6605d727dc62e17565a..202b267d8f653b8b45e188ed66c41c77f8814a02 100755 (executable)
@@ -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 */
index b69e388027d4f43d3f38423326f92f69e74a7f41..5c048f57ee0ca2d998273ff34c62e459ec68f368 100755 (executable)
@@ -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),
index be9762f6bb8172608df2432e47b65251023f28a1..f4a1c3785033a0bfc12e99f53c464aaf30c5e40b 100755 (executable)
@@ -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