rk3368 lcdc: fix deadlock when close lcdc and update reg
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / lcdc / rk3368_lcdc.c
index ba13a770bbb5b21a65ea94fb88c4912555b814d2..1a524ffd088ffdcb705f00631516906ae5c2a3ad 100755 (executable)
@@ -152,7 +152,7 @@ static int rk3368_lcdc_clk_enable(struct lcdc_device *lcdc_dev)
                clk_prepare_enable(lcdc_dev->hclk);
                clk_prepare_enable(lcdc_dev->dclk);
                clk_prepare_enable(lcdc_dev->aclk);
-               /*clk_prepare_enable(lcdc_dev->pd);*/
+               clk_prepare_enable(lcdc_dev->pd);
                spin_lock(&lcdc_dev->reg_lock);
                lcdc_dev->clk_on = 1;
                spin_unlock(&lcdc_dev->reg_lock);
@@ -175,7 +175,7 @@ static int rk3368_lcdc_clk_disable(struct lcdc_device *lcdc_dev)
                clk_disable_unprepare(lcdc_dev->dclk);
                clk_disable_unprepare(lcdc_dev->hclk);
                clk_disable_unprepare(lcdc_dev->aclk);
-               /*clk_disable_unprepare(lcdc_dev->pd);*/
+               clk_disable_unprepare(lcdc_dev->pd);
        }
 
        return 0;
@@ -416,9 +416,9 @@ static int rk3368_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
        lcdc_dev->hclk = devm_clk_get(lcdc_dev->dev, "hclk_lcdc");
        lcdc_dev->aclk = devm_clk_get(lcdc_dev->dev, "aclk_lcdc");
        lcdc_dev->dclk = devm_clk_get(lcdc_dev->dev, "dclk_lcdc");
-       /*lcdc_dev->pd = devm_clk_get(lcdc_dev->dev, "pd_lcdc");*/
+       lcdc_dev->pd = devm_clk_get(lcdc_dev->dev, "pd_lcdc");
 
-       if (/*IS_ERR(lcdc_dev->pd) || */(IS_ERR(lcdc_dev->aclk)) ||
+       if (IS_ERR(lcdc_dev->pd) || (IS_ERR(lcdc_dev->aclk)) ||
            (IS_ERR(lcdc_dev->dclk)) || (IS_ERR(lcdc_dev->hclk))) {
                dev_err(lcdc_dev->dev, "failed to get lcdc%d clk source\n",
                        lcdc_dev->id);
@@ -438,13 +438,21 @@ static int rk3368_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
                lcdc_grf_writel(lcdc_dev->pmugrf_base,
                                PMUGRF_SOC_CON0_VOP, v);
        }
+#if 0
        lcdc_writel(lcdc_dev, CABC_GAUSS_LINE0_0, 0x15110903);
        lcdc_writel(lcdc_dev, CABC_GAUSS_LINE0_1, 0x00030911);
        lcdc_writel(lcdc_dev, CABC_GAUSS_LINE1_0, 0x1a150b04);
        lcdc_writel(lcdc_dev, CABC_GAUSS_LINE1_1, 0x00040b15);
        lcdc_writel(lcdc_dev, CABC_GAUSS_LINE2_0, 0x15110903);
        lcdc_writel(lcdc_dev, CABC_GAUSS_LINE2_1, 0x00030911);
-
+#else
+       lcdc_writel(lcdc_dev, CABC_GAUSS_LINE0_0, 0x40000000);
+       lcdc_writel(lcdc_dev, CABC_GAUSS_LINE0_1, 0x0);
+       lcdc_writel(lcdc_dev, CABC_GAUSS_LINE1_0, 0x80000000);
+       lcdc_writel(lcdc_dev, CABC_GAUSS_LINE1_1, 0x0);
+       lcdc_writel(lcdc_dev, CABC_GAUSS_LINE2_0, 0x40000000);
+       lcdc_writel(lcdc_dev, CABC_GAUSS_LINE2_1, 0x0);
+#endif
        lcdc_writel(lcdc_dev, FRC_LOWER01_0, 0x12844821);
        lcdc_writel(lcdc_dev, FRC_LOWER01_1, 0x21488412);
        lcdc_writel(lcdc_dev, FRC_LOWER10_0, 0xa55a9696);
@@ -1384,7 +1392,6 @@ static int rk3368_lcdc_layer_update_regs(struct lcdc_device *lcdc_dev,
        int timeout;
        unsigned long flags;
 
-       spin_lock(&lcdc_dev->reg_lock);
        if (likely(lcdc_dev->clk_on)) {
                lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_STANDBY_EN,
                             v_STANDBY_EN(lcdc_dev->standby));
@@ -1397,7 +1404,6 @@ static int rk3368_lcdc_layer_update_regs(struct lcdc_device *lcdc_dev,
                /*rk3368_lcdc_post_cfg(dev_drv); */
                lcdc_cfg_done(lcdc_dev);
        }
-       spin_unlock(&lcdc_dev->reg_lock);
 
        /*if (dev_drv->wait_fs) { */
        if (0) {
@@ -1906,13 +1912,6 @@ static int rk3368_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                else
                        lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_DSP_LUT_EN,
                                     v_DSP_LUT_EN(1));
-               if (screen->cabc_lut == NULL) {
-                       lcdc_msk_reg(lcdc_dev, CABC_CTRL0, m_CABC_EN,
-                                    v_CABC_EN(0));
-               } else {
-                       lcdc_msk_reg(lcdc_dev, CABC_CTRL1, m_CABC_LUT_EN,
-                                    v_CABC_LUT_EN(1));
-               }
                rk3368_lcdc_bcsh_path_sel(dev_drv);
                rk3368_config_timing(dev_drv);
        }
@@ -2011,6 +2010,7 @@ static int rk3368_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
                /*rockchip_set_system_status(sys_status);*/
                rk3368_lcdc_pre_init(dev_drv);
                rk3368_lcdc_clk_enable(lcdc_dev);
+               rk3368_lcdc_enable_irq(dev_drv);
 #if defined(CONFIG_ROCKCHIP_IOMMU)
                if (dev_drv->iommu_enabled) {
                        if (!dev_drv->mmu_dev) {
@@ -2035,7 +2035,7 @@ static int rk3368_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
                   rk3368_lcdc_mmu_en(dev_drv); */
                if ((support_uboot_display() && (lcdc_dev->prop == PRMRY))) {
                        rk3368_lcdc_set_dclk(dev_drv, 0);
-                       rk3368_lcdc_enable_irq(dev_drv);
+                       /*rk3368_lcdc_enable_irq(dev_drv);*/
                } else {
                        rk3368_load_screen(dev_drv, 1);
                }
@@ -2273,6 +2273,7 @@ static int rk3368_lcdc_cal_scl_fac(struct rk_lcdc_win *win)
                break;
        case YUV420:
        case YUV420_A:
+       case YUV420_NV21:
                cbcr_srcW = srcW / 2;
                cbcr_dstW = dstW;
                cbcr_srcH = srcH / 2;
@@ -2329,6 +2330,7 @@ static int rk3368_lcdc_cal_scl_fac(struct rk_lcdc_win *win)
        /*line buffer mode */
        if ((win->area[0].format == YUV422) ||
            (win->area[0].format == YUV420) ||
+           (win->area[0].format == YUV420_NV21) ||
            (win->area[0].format == YUV422_A) ||
            (win->area[0].format == YUV420_A)) {
                if (win->cbr_hor_scl_mode == SCALE_DOWN) {
@@ -3016,11 +3018,13 @@ static int rk3368_lcdc_get_backlight_device(struct rk_lcdc_driver *dev_drv)
 {
        struct lcdc_device *lcdc_dev = container_of(dev_drv,
                                                    struct lcdc_device, driver);
-       /*struct device_node *backlight;*/
+       struct device_node *backlight;
+       struct property *prop;
+       u32 brightness_levels[256];
+       u32 length, max, last;
 
        if (lcdc_dev->backlight)
                return 0;
-#if 0
        backlight = of_parse_phandle(lcdc_dev->dev->of_node, "backlight", 0);
        if (backlight) {
                lcdc_dev->backlight = of_find_backlight_by_node(backlight);
@@ -3029,7 +3033,19 @@ static int rk3368_lcdc_get_backlight_device(struct rk_lcdc_driver *dev_drv)
        } else {
                dev_info(lcdc_dev->dev, "No find backlight device node\n");
        }
-#endif
+       prop = of_find_property(backlight, "brightness-levels", &length);
+       if (!prop)
+               return -EINVAL;
+       max = length / sizeof(u32);
+       last = max - 1;
+       if (!of_property_read_u32_array(backlight, "brightness-levels", brightness_levels, max)) {
+               if (brightness_levels[0] > brightness_levels[last])
+                       dev_drv->cabc_pwm_pol = 1;/*negative*/
+               else
+                       dev_drv->cabc_pwm_pol = 0;/*positive*/
+       } else {
+               dev_info(lcdc_dev->dev, "Can not read brightness-levels value\n");
+       }
        return 0;
 }
 
@@ -3910,16 +3926,26 @@ static int rk3368_lcdc_get_dsp_addr(struct rk_lcdc_driver *dev_drv,
        spin_unlock(&lcdc_dev->reg_lock);
        return 0;
 }
+static u32 pwm_period_hpr, pwm_duty_lpr;
+static u32 cabc_status = 0;
 
-static struct lcdc_cabc_mode cabc_mode[4] = {
-      /* calc,     up,     down,   global_limit   */
-       {5,    256,  256,   256},  /*mode 1   0*/
-       {5,    258,  253,   277},  /*mode 2   15%*/
-       {5,    259,  252,   330},  /*mode 3   40%*/
-       {5,    267,  244,   400},  /*mode 4   60%*/
-};
+int rk3368_lcdc_update_pwm(int bl_pwm_period, int bl_pwm_duty)
+{
+       pwm_period_hpr = bl_pwm_period;
+       pwm_duty_lpr = bl_pwm_duty;
+       /*pr_info("bl_pwm_period_hpr = 0x%x, bl_pwm_duty_lpr = 0x%x\n",
+       bl_pwm_period, bl_pwm_duty);*/
+       return 0;
+}
+
+int rk3368_lcdc_cabc_status(void)
+{
+       return cabc_status;
+}
 
-static int rk3368_lcdc_set_dsp_cabc(struct rk_lcdc_driver *dev_drv, int mode)
+static int rk3368_lcdc_set_dsp_cabc(struct rk_lcdc_driver *dev_drv,
+                                   int mode, int calc, int up,
+                                   int down, int global)
 {
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
@@ -3937,9 +3963,13 @@ static int rk3368_lcdc_set_dsp_cabc(struct rk_lcdc_driver *dev_drv, int mode)
                cabc_lut = screen->cabc_lut;
        }
 
+       if (!screen->cabc_gamma_base) {
+               pr_err("screen cabc_gamma_base no config, so not open cabc\n");
+               return 0;
+       }
        dev_drv->cabc_mode = mode;
        cabc_en = (mode > 0) ? 1 : 0;
-
+       rk3368_lcdc_get_backlight_device(dev_drv);
        if (cabc_en == 0) {
                spin_lock(&lcdc_dev->reg_lock);
                if (lcdc_dev->clk_on) {
@@ -3947,20 +3977,30 @@ static int rk3368_lcdc_set_dsp_cabc(struct rk_lcdc_driver *dev_drv, int mode)
                                     m_CABC_EN, v_CABC_EN(0));
                        lcdc_cfg_done(lcdc_dev);
                }
+               pr_info("mode = 0, close cabc\n");
+               rk_pwm_set(pwm_period_hpr, pwm_duty_lpr);
+               cabc_status = 0;
                spin_unlock(&lcdc_dev->reg_lock);
                return 0;
        }
+       if (cabc_status == 0) { /*get from pwm*/
+               rk_pwm_get(&pwm_period_hpr, &pwm_duty_lpr);
+               pr_info("pwm_period_hpr=0x%x, pwm_duty_lpr=0x%x\n",
+                       pwm_period_hpr, pwm_duty_lpr);
+       }
 
        total_pixel = screen->mode.xres * screen->mode.yres;
-       pixel_num = 1000 - (cabc_mode[mode - 1].pixel_num);
+       pixel_num = 1000 - calc;
        calc_pixel = (total_pixel * pixel_num) / 1000;
-       stage_up = cabc_mode[mode - 1].stage_up;
-       stage_down = cabc_mode[mode - 1].stage_down;
-       global_su = cabc_mode[mode - 1].global_su;
+       stage_up = up;
+       stage_down = down;
+       global_su = global;
+       pr_info("enable cabc:mode=%d, calc=%d, up=%d, down=%d, global=%d\n",
+               mode, calc, stage_up, stage_down, global_su);
 
        stage_up_rec = 256 * 256 / stage_up;
        stage_down_rec = 256 * 256 / stage_down;
-       global_su_rec = (256 * 256 / global_su) - 1;
+       global_su_rec = (256 * 256 / global_su);
        gamma_global_su_rec = cabc_lut[global_su_rec];
 
        spin_lock(&lcdc_dev->reg_lock);
@@ -3990,6 +4030,7 @@ static int rk3368_lcdc_set_dsp_cabc(struct rk_lcdc_driver *dev_drv, int mode)
                lcdc_msk_reg(lcdc_dev, CABC_CTRL3, mask, val);
                lcdc_cfg_done(lcdc_dev);
        }
+       cabc_status = 1;
        spin_unlock(&lcdc_dev->reg_lock);
 
        return 0;
@@ -4328,7 +4369,10 @@ static irqreturn_t rk3368_lcdc_isr(int irq, void *dev_id)
        struct lcdc_device *lcdc_dev = (struct lcdc_device *)dev_id;
        ktime_t timestamp = ktime_get();
        u32 intr_status;
-
+       u32 scale_global_limit, scale_global_limit_reg;
+       u32 cabc_pwm_lut_value;
+       int pwm_plus;
+       int *cabc_gamma_base = NULL;
        intr_status = lcdc_readl(lcdc_dev, INTR_STATUS);
 
        if (intr_status & m_FS_INTR_STS) {
@@ -4346,13 +4390,34 @@ static irqreturn_t rk3368_lcdc_isr(int irq, void *dev_id)
 #endif
                lcdc_dev->driver.vsync_info.timestamp = timestamp;
                wake_up_interruptible_all(&lcdc_dev->driver.vsync_info.wait);
-
        } else if (intr_status & m_LINE_FLAG0_INTR_STS) {
                lcdc_dev->driver.frame_time.last_framedone_t =
-                   lcdc_dev->driver.frame_time.framedone_t;
+                       lcdc_dev->driver.frame_time.framedone_t;
                lcdc_dev->driver.frame_time.framedone_t = cpu_clock(0);
                lcdc_msk_reg(lcdc_dev, INTR_CLEAR, m_LINE_FLAG0_INTR_CLR,
                             v_LINE_FLAG0_INTR_CLR(1));
+
+               if (cabc_status == 1) {
+                       cabc_gamma_base =
+                               lcdc_dev->driver.cur_screen->cabc_gamma_base;
+                       scale_global_limit  = lcdc_readl(lcdc_dev, CABC_DEBUG2);
+                       scale_global_limit_reg = scale_global_limit;
+                       scale_global_limit >>= 16;
+                       scale_global_limit &= 0xff;
+
+                       if (lcdc_dev->driver.cabc_pwm_pol == 1) {/*negative*/
+                               pwm_plus = pwm_period_hpr - pwm_duty_lpr;
+                               cabc_pwm_lut_value =
+                                       pwm_period_hpr -
+                                       ((cabc_gamma_base[scale_global_limit] * pwm_plus) >> 16);
+                       } else {/*positive*/
+                               pwm_plus = pwm_duty_lpr;
+                               cabc_pwm_lut_value =
+                                       cabc_gamma_base[scale_global_limit] *
+                                       pwm_plus >> 16;
+                       }
+                       rk_pwm_set(pwm_period_hpr, cabc_pwm_lut_value);
+               }
        } else if (intr_status & m_LINE_FLAG1_INTR_STS) {
                /*line flag1 */
                lcdc_msk_reg(lcdc_dev, INTR_CLEAR, m_LINE_FLAG1_INTR_CLR,
@@ -4511,6 +4576,7 @@ static int rk3368_lcdc_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "can't find lcdc pmu grf property\n");
                return PTR_ERR(lcdc_dev->pmugrf_base);
        }
+
        lcdc_dev->id = 0;
        dev_set_name(lcdc_dev->dev, "lcdc%d", lcdc_dev->id);
        dev_drv = &lcdc_dev->driver;