drm/rockchip: vop: add rk3366 vop lit support
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / rockchip / rockchip_drm_vop.c
index 67ece59d3cf0b0fd0a7dafcd24b1b5930e9f7bc9..7608a02d72f0255456476713f613c947b5840219 100644 (file)
@@ -41,6 +41,7 @@
 #include "rockchip_drm_gem.h"
 #include "rockchip_drm_fb.h"
 #include "rockchip_drm_vop.h"
+#include "rockchip_drm_backlight.h"
 
 #define VOP_REG_SUPPORT(vop, reg) \
                (!reg.major || (reg.major == VOP_MAJOR(vop->data->version) && \
@@ -938,6 +939,7 @@ err_disable_hclk:
 static void vop_initial(struct drm_crtc *crtc)
 {
        struct vop *vop = to_vop(crtc);
+       uint32_t irqs;
        int i;
 
        vop_power_enable(crtc);
@@ -971,6 +973,12 @@ static void vop_initial(struct drm_crtc *crtc)
                VOP_WIN_SET(vop, win, gate, 1);
        }
        VOP_CTRL_SET(vop, afbdc_en, 0);
+
+       irqs = BUS_ERROR_INTR | WIN0_EMPTY_INTR | WIN1_EMPTY_INTR |
+               WIN2_EMPTY_INTR | WIN3_EMPTY_INTR | HWC_EMPTY_INTR |
+               POST_BUF_EMPTY_INTR;
+       VOP_INTR_SET_TYPE(vop, clear, irqs, 1);
+       VOP_INTR_SET_TYPE(vop, enable, irqs, 1);
 }
 
 static void vop_crtc_disable(struct drm_crtc *crtc)
@@ -1673,8 +1681,8 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
        mutex_lock(&vop->vop_lock);
        vop_initial(crtc);
 
-       val = BIT(DCLK_INVERT);
-       val |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ?
+       VOP_CTRL_SET(vop, dclk_pol, 1);
+       val = (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ?
                   0 : BIT(HSYNC_POSITIVE);
        val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ?
                   0 : BIT(VSYNC_POSITIVE);
@@ -1690,21 +1698,28 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
        case DRM_MODE_CONNECTOR_LVDS:
                VOP_CTRL_SET(vop, rgb_en, 1);
                VOP_CTRL_SET(vop, rgb_pin_pol, val);
+               VOP_CTRL_SET(vop, rgb_dclk_pol, 1);
+               VOP_CTRL_SET(vop, lvds_en, 1);
+               VOP_CTRL_SET(vop, lvds_pin_pol, val);
+               VOP_CTRL_SET(vop, lvds_dclk_pol, 1);
                break;
        case DRM_MODE_CONNECTOR_eDP:
                VOP_CTRL_SET(vop, edp_en, 1);
                VOP_CTRL_SET(vop, edp_pin_pol, val);
+               VOP_CTRL_SET(vop, edp_dclk_pol, 1);
                break;
        case DRM_MODE_CONNECTOR_HDMIA:
                VOP_CTRL_SET(vop, hdmi_en, 1);
                VOP_CTRL_SET(vop, hdmi_pin_pol, val);
+               VOP_CTRL_SET(vop, hdmi_dclk_pol, 1);
                break;
        case DRM_MODE_CONNECTOR_DSI:
                VOP_CTRL_SET(vop, mipi_en, 1);
                VOP_CTRL_SET(vop, mipi_pin_pol, val);
+               VOP_CTRL_SET(vop, mipi_dclk_pol, 1);
                break;
        case DRM_MODE_CONNECTOR_DisplayPort:
-               val &= ~BIT(DCLK_INVERT);
+               VOP_CTRL_SET(vop, dp_dclk_pol, 0);
                VOP_CTRL_SET(vop, dp_pin_pol, val);
                VOP_CTRL_SET(vop, dp_en, 1);
                break;
@@ -1763,9 +1778,18 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
                     s->output_mode == ROCKCHIP_OUT_MODE_YUV420 ? 1 : 0);
        VOP_CTRL_SET(vop, overlay_mode, is_yuv_output(s->bus_format));
        VOP_CTRL_SET(vop, dsp_out_yuv, is_yuv_output(s->bus_format));
-       VOP_CTRL_SET(vop, dsp_background,
-                    is_yuv_output(s->bus_format) ? 0x20010200 : 0);
 
+       /*
+        * Background color is 10bit depth if vop version >= 3.5
+        */
+       if (!is_yuv_output(s->bus_format))
+               val = 0;
+       else if (VOP_MAJOR(vop->data->version) == 3 &&
+                VOP_MINOR(vop->data->version) >= 5)
+               val = 0x20010200;
+       else
+               val = 0x801080;
+       VOP_CTRL_SET(vop, dsp_background, val);
        VOP_CTRL_SET(vop, htotal_pw, (htotal << 16) | hsync_len);
        val = hact_st << 16;
        val |= hact_end;
@@ -2045,7 +2069,12 @@ static void vop_post_config(struct drm_crtc *crtc)
        val = scl_cal_scale2(vdisplay, vsize) << 16;
        val |= scl_cal_scale2(hdisplay, hsize);
        VOP_CTRL_SET(vop, post_scl_factor, val);
-       VOP_CTRL_SET(vop, post_scl_ctrl, 0x3);
+
+#define POST_HORIZONTAL_SCALEDOWN_EN(x)                ((x) << 0)
+#define POST_VERTICAL_SCALEDOWN_EN(x)          ((x) << 1)
+       VOP_CTRL_SET(vop, post_scl_ctrl,
+                    POST_HORIZONTAL_SCALEDOWN_EN(hdisplay != hsize) ||
+                    POST_VERTICAL_SCALEDOWN_EN(vdisplay != vsize));
        if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
                u16 vact_st_f1 = vtotal + vact_st + 1;
                u16 vact_end_f1 = vact_st_f1 + vsize;
@@ -2608,6 +2637,23 @@ static irqreturn_t vop_isr(int irq, void *data)
                ret = IRQ_HANDLED;
        }
 
+#define ERROR_HANDLER(x) \
+       do { \
+               if (active_irqs & x##_INTR) {\
+                       DRM_DEV_ERROR_RATELIMITED(vop->dev, #x " irq err\n"); \
+                       active_irqs &= ~x##_INTR; \
+                       ret = IRQ_HANDLED; \
+               } \
+       } while (0)
+
+       ERROR_HANDLER(BUS_ERROR);
+       ERROR_HANDLER(WIN0_EMPTY);
+       ERROR_HANDLER(WIN1_EMPTY);
+       ERROR_HANDLER(WIN2_EMPTY);
+       ERROR_HANDLER(WIN3_EMPTY);
+       ERROR_HANDLER(HWC_EMPTY);
+       ERROR_HANDLER(POST_BUF_EMPTY);
+
        /* Unhandled irqs are spurious. */
        if (active_irqs)
                DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs);
@@ -3003,6 +3049,27 @@ int rockchip_drm_register_notifier_to_dmc(struct devfreq *devfreq)
 }
 EXPORT_SYMBOL(rockchip_drm_register_notifier_to_dmc);
 
+static void vop_backlight_config_done(struct device *dev, bool async)
+{
+       struct vop *vop = dev_get_drvdata(dev);
+
+       if (vop && vop->is_enabled) {
+               int dle;
+
+               vop_cfg_done(vop);
+               if (!async) {
+                       #define CTRL_GET(name) VOP_CTRL_GET(vop, name)
+                       readx_poll_timeout(CTRL_GET, cfg_done,
+                                          dle, !dle, 5, 33333);
+                       #undef CTRL_GET
+               }
+       }
+}
+
+static const struct rockchip_sub_backlight_ops rockchip_sub_backlight_ops = {
+       .config_done = vop_backlight_config_done,
+};
+
 static int vop_bind(struct device *dev, struct device *master, void *data)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -3138,6 +3205,9 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
 
        pm_runtime_enable(&pdev->dev);
 
+       of_rockchip_drm_sub_backlight_register(dev, &vop->crtc,
+                                              &rockchip_sub_backlight_ops);
+
        dmc_vop = vop;
 
        return 0;