drm/rockchip: vop: support csc convert for win0/1
authorMark Yao <mark.yao@rock-chips.com>
Tue, 6 Sep 2016 09:18:38 +0000 (17:18 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Thu, 22 Sep 2016 12:46:47 +0000 (20:46 +0800)
Change-Id: I7be5dfb7d2711de5a5aeed730aea0ffd9e080945
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.h
drivers/gpu/drm/rockchip/rockchip_vop_reg.c

index 7255232b5a285f03da73c856699130146b572db8..fe4b96cbd42044d017ab938ac396f5af92946dd0 100644 (file)
@@ -72,6 +72,8 @@
 
 #define VOP_WIN_SET(x, win, name, v) \
                REG_SET(x, name, win->offset, VOP_WIN_NAME(win, name), v, true)
 
 #define VOP_WIN_SET(x, win, name, v) \
                REG_SET(x, name, win->offset, VOP_WIN_NAME(win, name), v, true)
+#define VOP_WIN_SET_EXT(x, win, ext, name, v) \
+               REG_SET(x, name, win->offset, win->ext->name, v, true)
 #define VOP_SCL_SET(x, win, name, v) \
                REG_SET(x, name, win->offset, win->phy->scl->name, v, true)
 #define VOP_SCL_SET_EXT(x, win, name, v) \
 #define VOP_SCL_SET(x, win, name, v) \
                REG_SET(x, name, win->offset, win->phy->scl->name, v, true)
 #define VOP_SCL_SET_EXT(x, win, name, v) \
@@ -130,6 +132,9 @@ struct vop_plane_state {
        struct drm_rect dest;
        dma_addr_t yrgb_mst;
        dma_addr_t uv_mst;
        struct drm_rect dest;
        dma_addr_t yrgb_mst;
        dma_addr_t uv_mst;
+       const uint32_t *y2r_table;
+       const uint32_t *r2r_table;
+       const uint32_t *r2y_table;
        bool enable;
 };
 
        bool enable;
 };
 
@@ -142,6 +147,7 @@ struct vop_win {
        uint32_t offset;
        enum drm_plane_type type;
        const struct vop_win_phy *phy;
        uint32_t offset;
        enum drm_plane_type type;
        const struct vop_win_phy *phy;
+       const struct vop_csc *csc;
        const uint32_t *data_formats;
        uint32_t nformats;
        struct vop *vop;
        const uint32_t *data_formats;
        uint32_t nformats;
        struct vop *vop;
@@ -258,6 +264,17 @@ static inline uint32_t vop_get_intr_type(struct vop *vop,
        return ret;
 }
 
        return ret;
 }
 
+static void vop_load_csc_table(struct vop *vop, u32 offset, const u32 *table)
+{
+       int i;
+
+       if (!table)
+               return;
+
+       for (i = 0; i < 8; i++)
+               vop_writel(vop, offset + i * 4, table[i]);
+}
+
 static inline void vop_cfg_done(struct vop *vop)
 {
        VOP_CTRL_SET(vop, cfg_done, 1);
 static inline void vop_cfg_done(struct vop *vop)
 {
        VOP_CTRL_SET(vop, cfg_done, 1);
@@ -483,6 +500,140 @@ static void scl_vop_cal_scl_fac(struct vop *vop, struct vop_win *win,
        }
 }
 
        }
 }
 
+/*
+ * rk3399 colorspace path:
+ *      Input        Win csc                     Output
+ * 1. YUV(2020)  --> Y2R->2020To709->R2Y   --> YUV_OUTPUT(601/709)
+ *    RGB        --> R2Y                  __/
+ *
+ * 2. YUV(2020)  --> bypasss               --> YUV_OUTPUT(2020)
+ *    RGB        --> 709To2020->R2Y       __/
+ *
+ * 3. YUV(2020)  --> Y2R->2020To709        --> RGB_OUTPUT(709)
+ *    RGB        --> R2Y                  __/
+ *
+ * 4. YUV(601/709)-> Y2R->709To2020->R2Y   --> YUV_OUTPUT(2020)
+ *    RGB        --> 709To2020->R2Y       __/
+ *
+ * 5. YUV(601/709)-> bypass                --> YUV_OUTPUT(709)
+ *    RGB        --> R2Y                  __/
+ *
+ * 6. YUV(601/709)-> bypass                --> YUV_OUTPUT(601)
+ *    RGB        --> R2Y(601)             __/
+ *
+ * 7. YUV        --> Y2R(709)              --> RGB_OUTPUT(709)
+ *    RGB        --> bypass               __/
+ *
+ * 8. RGB        --> 709To2020->R2Y        --> YUV_OUTPUT(2020)
+ *
+ * 9. RGB        --> R2Y(709)              --> YUV_OUTPUT(709)
+ *
+ * 10. RGB       --> R2Y(601)              --> YUV_OUTPUT(601)
+ *
+ * 11. RGB       --> bypass                --> RGB_OUTPUT(709)
+ */
+static int vop_csc_setup(const struct vop_csc_table *csc_table,
+                        bool is_input_yuv, bool is_output_yuv,
+                        int input_csc, int output_csc,
+                        const uint32_t **y2r_table,
+                        const uint32_t **r2r_table,
+                        const uint32_t **r2y_table)
+{
+       *y2r_table = NULL;
+       *r2r_table = NULL;
+       *r2y_table = NULL;
+
+       if (is_output_yuv) {
+               if (output_csc == CSC_BT2020) {
+                       if (is_input_yuv) {
+                               if (input_csc == CSC_BT2020)
+                                       return 0;
+                               *y2r_table = csc_table->y2r_bt709;
+                       }
+                       if (input_csc != CSC_BT2020)
+                               *r2r_table = csc_table->r2r_bt709_to_bt2020;
+                       *r2y_table = csc_table->r2y_bt2020;
+               } else {
+                       if (is_input_yuv && input_csc == CSC_BT2020)
+                               *y2r_table = csc_table->y2r_bt2020;
+                       if (input_csc == CSC_BT2020)
+                               *r2r_table = csc_table->r2r_bt2020_to_bt709;
+                       if (!is_input_yuv || y2r_table) {
+                               if (output_csc == CSC_BT709)
+                                       *r2y_table = csc_table->r2y_bt709;
+                               else
+                                       *r2y_table = csc_table->r2y_bt601;
+                       }
+               }
+
+       } else {
+               if (!is_input_yuv)
+                       return 0;
+
+               /*
+                * is possible use bt2020 on rgb mode?
+                */
+               if (WARN_ON(output_csc == CSC_BT2020))
+                       return -EINVAL;
+
+               if (input_csc == CSC_BT2020)
+                       *y2r_table = csc_table->y2r_bt2020;
+               else if (input_csc == CSC_BT709)
+                       *y2r_table = csc_table->y2r_bt709;
+               else
+                       *y2r_table = csc_table->y2r_bt601;
+
+               if (input_csc == CSC_BT2020)
+                       /*
+                        * We don't have bt601 to bt709 table, force use bt709.
+                        */
+                       *r2r_table = csc_table->r2r_bt2020_to_bt709;
+       }
+
+       return 0;
+}
+
+static int vop_csc_atomic_check(struct drm_crtc *crtc,
+                               struct drm_crtc_state *crtc_state)
+{
+       struct vop *vop = to_vop(crtc);
+       struct drm_atomic_state *state = crtc_state->state;
+       const struct vop_csc_table *csc_table = vop->data->csc_table;
+       struct drm_plane_state *pstate;
+       struct drm_plane *plane;
+       bool is_yuv;
+       int ret;
+
+       if (!csc_table)
+               return 0;
+
+       drm_atomic_crtc_state_for_each_plane(plane, crtc_state) {
+               struct vop_plane_state *vop_plane_state;
+
+               pstate = drm_atomic_get_plane_state(state, plane);
+               if (IS_ERR(pstate))
+                       return PTR_ERR(pstate);
+               vop_plane_state = to_vop_plane_state(pstate);
+
+               if (!pstate->fb)
+                       continue;
+               is_yuv = is_yuv_support(pstate->fb->pixel_format);
+
+               /*
+                * TODO: force set input and output csc mode.
+                */
+               ret = vop_csc_setup(csc_table, is_yuv, false,
+                                   CSC_BT709, CSC_BT709,
+                                   &vop_plane_state->y2r_table,
+                                   &vop_plane_state->r2r_table,
+                                   &vop_plane_state->r2y_table);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static void vop_dsp_hold_valid_irq_enable(struct vop *vop)
 {
        unsigned long flags;
 static void vop_dsp_hold_valid_irq_enable(struct vop *vop)
 {
        unsigned long flags;
@@ -774,6 +925,9 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
        uint32_t act_info, dsp_info, dsp_st;
        struct drm_rect *src = &vop_plane_state->src;
        struct drm_rect *dest = &vop_plane_state->dest;
        uint32_t act_info, dsp_info, dsp_st;
        struct drm_rect *src = &vop_plane_state->src;
        struct drm_rect *dest = &vop_plane_state->dest;
+       const uint32_t *y2r_table = vop_plane_state->y2r_table;
+       const uint32_t *r2r_table = vop_plane_state->r2r_table;
+       const uint32_t *r2y_table = vop_plane_state->r2y_table;
        int ymirror, xmirror;
        uint32_t val;
        bool rb_swap;
        int ymirror, xmirror;
        uint32_t val;
        bool rb_swap;
@@ -843,6 +997,14 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
                VOP_WIN_SET(vop, win, alpha_en, 0);
        }
 
                VOP_WIN_SET(vop, win, alpha_en, 0);
        }
 
+       if (win->csc) {
+               vop_load_csc_table(vop, win->csc->y2r_offset, y2r_table);
+               vop_load_csc_table(vop, win->csc->r2r_offset, r2r_table);
+               vop_load_csc_table(vop, win->csc->r2r_offset, r2y_table);
+               VOP_WIN_SET_EXT(vop, win, csc, y2r_en, !!y2r_table);
+               VOP_WIN_SET_EXT(vop, win, csc, r2r_en, !!r2r_table);
+               VOP_WIN_SET_EXT(vop, win, csc, r2y_en, !!r2y_table);
+       }
        VOP_WIN_SET(vop, win, enable, 1);
        spin_unlock(&vop->reg_lock);
        vop->is_iommu_needed = true;
        VOP_WIN_SET(vop, win, enable, 1);
        spin_unlock(&vop->reg_lock);
        vop->is_iommu_needed = true;
@@ -1164,6 +1326,10 @@ static int vop_crtc_atomic_check(struct drm_crtc *crtc,
        int dsp_layer_sel = 0;
        int i, j, cnt = 0, ret = 0;
 
        int dsp_layer_sel = 0;
        int i, j, cnt = 0, ret = 0;
 
+       ret = vop_csc_atomic_check(crtc, crtc_state);
+       if (ret)
+               return ret;
+
        pzpos = kmalloc_array(vop_data->win_size, sizeof(*pzpos), GFP_KERNEL);
        if (!pzpos)
                return -ENOMEM;
        pzpos = kmalloc_array(vop_data->win_size, sizeof(*pzpos), GFP_KERNEL);
        if (!pzpos)
                return -ENOMEM;
@@ -1576,6 +1742,7 @@ static int vop_win_init(struct vop *vop)
                        continue;
 
                vop_win->phy = win_data->phy;
                        continue;
 
                vop_win->phy = win_data->phy;
+               vop_win->csc = win_data->csc;
                vop_win->offset = win_data->base;
                vop_win->type = win_data->type;
                vop_win->data_formats = win_data->phy->data_formats;
                vop_win->offset = win_data->base;
                vop_win->type = win_data->type;
                vop_win->data_formats = win_data->phy->data_formats;
index c2233ce31757056e0ad88519b432b47d23569d90..1731e184396c475c1546d550830f58568d6aab71 100644 (file)
 #define VOP_MAJOR(version)     ((version) >> 8)
 #define VOP_MINOR(version)     ((version) & 0xff)
 
 #define VOP_MAJOR(version)     ((version) >> 8)
 #define VOP_MINOR(version)     ((version) & 0xff)
 
+enum vop_csc_format {
+       CSC_BT601,
+       CSC_BT709,
+       CSC_BT2020,
+};
+
+enum vop_csc_mode {
+       CSC_RGB,
+       CSC_YUV,
+};
+
 enum vop_data_format {
        VOP_FMT_ARGB8888 = 0,
        VOP_FMT_RGB888,
 enum vop_data_format {
        VOP_FMT_ARGB8888 = 0,
        VOP_FMT_RGB888,
@@ -47,6 +58,16 @@ struct vop_reg {
        uint32_t write_mask:1;
 };
 
        uint32_t write_mask:1;
 };
 
+struct vop_csc {
+       struct vop_reg y2r_en;
+       struct vop_reg r2r_en;
+       struct vop_reg r2y_en;
+
+       uint32_t y2r_offset;
+       uint32_t r2r_offset;
+       uint32_t r2y_offset;
+};
+
 struct vop_ctrl {
        struct vop_reg standby;
        struct vop_reg htotal_pw;
 struct vop_ctrl {
        struct vop_reg standby;
        struct vop_reg htotal_pw;
@@ -136,6 +157,39 @@ struct vop_scl_regs {
        struct vop_reg scale_cbcr_y;
 };
 
        struct vop_reg scale_cbcr_y;
 };
 
+struct vop_csc_table {
+       const uint32_t *y2r_bt601;
+       const uint32_t *y2r_bt601_12_235;
+       const uint32_t *y2r_bt601_10bit;
+       const uint32_t *y2r_bt601_10bit_12_235;
+       const uint32_t *r2y_bt601;
+       const uint32_t *r2y_bt601_12_235;
+       const uint32_t *r2y_bt601_10bit;
+       const uint32_t *r2y_bt601_10bit_12_235;
+
+       const uint32_t *y2r_bt709;
+       const uint32_t *y2r_bt709_10bit;
+       const uint32_t *r2y_bt709;
+       const uint32_t *r2y_bt709_10bit;
+
+       const uint32_t *y2r_bt2020;
+       const uint32_t *r2y_bt2020;
+
+       const uint32_t *r2r_bt709_to_bt2020;
+       const uint32_t *r2r_bt2020_to_bt709;
+};
+
+enum {
+       VOP_CSC_Y2R_BT601,
+       VOP_CSC_Y2R_BT709,
+       VOP_CSC_Y2R_BT2020,
+       VOP_CSC_R2Y_BT601,
+       VOP_CSC_R2Y_BT709,
+       VOP_CSC_R2Y_BT2020,
+       VOP_CSC_R2R_BT2020_TO_BT709,
+       VOP_CSC_R2R_BT709_TO_2020,
+};
+
 struct vop_win_phy {
        const struct vop_scl_regs *scl;
        const uint32_t *data_formats;
 struct vop_win_phy {
        const struct vop_scl_regs *scl;
        const uint32_t *data_formats;
@@ -168,6 +222,7 @@ struct vop_win_data {
        enum drm_plane_type type;
        const struct vop_win_phy *phy;
        const struct vop_win_phy **area;
        enum drm_plane_type type;
        const struct vop_win_phy *phy;
        const struct vop_win_phy **area;
+       const struct vop_csc *csc;
        unsigned int area_size;
 };
 
        unsigned int area_size;
 };
 
@@ -179,6 +234,7 @@ struct vop_data {
        const struct vop_ctrl *ctrl;
        const struct vop_intr *intr;
        const struct vop_win_data *win;
        const struct vop_ctrl *ctrl;
        const struct vop_intr *intr;
        const struct vop_win_data *win;
+       const struct vop_csc_table *csc_table;
        unsigned int win_size;
        uint32_t version;
        u64 feature;
        unsigned int win_size;
        uint32_t version;
        u64 feature;
index 4298e091350fff52a761eef03e6ccb282a26c1b1..f77a6522e063d9a1571f079b40ddc5171d82c33d 100644 (file)
@@ -371,17 +371,116 @@ static const struct vop_data rk3366_vop = {
        .win_size = ARRAY_SIZE(rk3368_vop_win_data),
 };
 
        .win_size = ARRAY_SIZE(rk3368_vop_win_data),
 };
 
+static const uint32_t vop_csc_y2r_bt601[] = {
+       0x00000400, 0x0400059c, 0xfd25fea0, 0x07170400,
+       0x00000000, 0xfffecab4, 0x00087932, 0xfff1d4f2,
+};
+
+static const uint32_t vop_csc_y2r_bt601_12_235[] = {
+       0x000004a8, 0x04a80662, 0xfcbffe6f, 0x081204a8,
+       0x00000000, 0xfff2134e, 0x00087b58, 0xffeeb4b0,
+};
+
+static const uint32_t vop_csc_r2y_bt601[] = {
+       0x02590132, 0xff530075, 0x0200fead, 0xfe530200,
+       0x0000ffad, 0x00000200, 0x00080200, 0x00080200,
+};
+
+static const uint32_t vop_csc_r2y_bt601_12_235[] = {
+       0x02040107, 0xff680064, 0x01c2fed6, 0xffb7fe87,
+       0x0000ffb7, 0x00010200, 0x00080200, 0x00080200,
+};
+
+static const uint32_t vop_csc_y2r_bt709[] = {
+       0x000004a8, 0x04a8072c, 0xfddeff26, 0x087304a8,
+       0x00000000, 0xfff08077, 0x0004cfed, 0xffedf1b8,
+};
+
+static const uint32_t vop_csc_r2y_bt709[] = {
+       0x027500bb, 0xff99003f, 0x01c2fea5, 0xfe6801c2,
+       0xffd7fe68, 0x00010200, 0x00080200, 0x00080200,
+};
+
+static const uint32_t vop_csc_y2r_bt2020[] = {
+       0x000004a8, 0x04a806b6, 0xfd66ff40, 0x089004a8,
+       0x00000000, 0xfff16bfc, 0x00058ae9, 0xffedb828,
+};
+
+static const uint32_t vop_csc_r2y_bt2020[] = {
+       0x025300e6, 0xff830034, 0x01c1febd, 0xfe6401c1,
+       0x0000ffdc, 0x00010200, 0x00080200, 0x00080200,
+};
+
+static const uint32_t vop_csc_r2r_bt709_to_bt2020[] = {
+       0xfda606a4, 0xff80ffb5, 0xfff80488, 0xff99ffed,
+       0x0000047a, 0x00000200, 0x00000200, 0x00000200,
+};
+
+static const uint32_t vop_csc_r2r_bt2020_to_bt709[] = {
+       0x01510282, 0x0047002c, 0x000c03ae, 0x005a0011,
+       0x00000394, 0x00000200, 0x00000200, 0x00000200,
+};
+
+static const struct vop_csc_table rk3399_csc_table = {
+       .y2r_bt601              = vop_csc_y2r_bt601,
+       .y2r_bt601_12_235       = vop_csc_y2r_bt601_12_235,
+       .r2y_bt601              = vop_csc_r2y_bt601,
+       .r2y_bt601_12_235       = vop_csc_r2y_bt601_12_235,
+
+       .y2r_bt709              = vop_csc_y2r_bt709,
+       .r2y_bt709              = vop_csc_r2y_bt709,
+
+       .y2r_bt2020             = vop_csc_y2r_bt2020,
+       .r2y_bt2020             = vop_csc_r2y_bt2020,
+
+       .r2r_bt709_to_bt2020    = vop_csc_r2r_bt709_to_bt2020,
+       .r2r_bt2020_to_bt709    = vop_csc_r2r_bt2020_to_bt709,
+};
+
+static const struct vop_csc rk3399_win0_csc = {
+       .r2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 0),
+       .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1),
+       .r2y_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 2),
+       .y2r_offset = RK3399_WIN0_YUV2YUV_Y2R,
+       .r2r_offset = RK3399_WIN0_YUV2YUV_3X3,
+       .r2y_offset = RK3399_WIN0_YUV2YUV_R2Y,
+};
+
+static const struct vop_csc rk3399_win1_csc = {
+       .r2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 8),
+       .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9),
+       .r2y_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 10),
+       .y2r_offset = RK3399_WIN1_YUV2YUV_Y2R,
+       .r2r_offset = RK3399_WIN1_YUV2YUV_3X3,
+       .r2y_offset = RK3399_WIN1_YUV2YUV_R2Y,
+};
+
+static const struct vop_win_data rk3399_vop_win_data[] = {
+       { .base = 0x00, .phy = &rk3288_win01_data, .csc = &rk3399_win0_csc,
+         .type = DRM_PLANE_TYPE_PRIMARY },
+       { .base = 0x40, .phy = &rk3288_win01_data, .csc = &rk3399_win1_csc,
+         .type = DRM_PLANE_TYPE_OVERLAY },
+       { .base = 0x00, .phy = &rk3368_win23_data,
+         .type = DRM_PLANE_TYPE_OVERLAY,
+         .area = rk3368_area_data,
+         .area_size = ARRAY_SIZE(rk3368_area_data), },
+       { .base = 0x50, .phy = &rk3368_win23_data,
+         .type = DRM_PLANE_TYPE_CURSOR,
+         .area = rk3368_area_data,
+         .area_size = ARRAY_SIZE(rk3368_area_data), },
+};
+
 static const struct vop_data rk3399_vop_big = {
        .version = VOP_VERSION(3, 5),
        .feature = VOP_FEATURE_OUTPUT_10BIT,
        .intr = &rk3366_vop_intr,
        .ctrl = &rk3288_ctrl_data,
 static const struct vop_data rk3399_vop_big = {
        .version = VOP_VERSION(3, 5),
        .feature = VOP_FEATURE_OUTPUT_10BIT,
        .intr = &rk3366_vop_intr,
        .ctrl = &rk3288_ctrl_data,
-       .win = rk3368_vop_win_data,
-       .win_size = ARRAY_SIZE(rk3368_vop_win_data),
+       .win = rk3399_vop_win_data,
+       .win_size = ARRAY_SIZE(rk3399_vop_win_data),
 };
 
 static const struct vop_win_data rk3399_vop_lit_win_data[] = {
 };
 
 static const struct vop_win_data rk3399_vop_lit_win_data[] = {
-       { .base = 0x00, .phy = &rk3288_win01_data,
+       { .base = 0x00, .phy = &rk3288_win01_data, .csc = &rk3399_win0_csc,
          .type = DRM_PLANE_TYPE_PRIMARY },
        { .phy = NULL },
        { .base = 0x00, .phy = &rk3368_win23_data,
          .type = DRM_PLANE_TYPE_PRIMARY },
        { .phy = NULL },
        { .base = 0x00, .phy = &rk3368_win23_data,
@@ -394,6 +493,7 @@ static const struct vop_win_data rk3399_vop_lit_win_data[] = {
 
 static const struct vop_data rk3399_vop_lit = {
        .version = VOP_VERSION(3, 6),
 
 static const struct vop_data rk3399_vop_lit = {
        .version = VOP_VERSION(3, 6),
+       .csc_table = &rk3399_csc_table,
        .intr = &rk3366_vop_intr,
        .ctrl = &rk3288_ctrl_data,
        .win = rk3399_vop_lit_win_data,
        .intr = &rk3366_vop_intr,
        .ctrl = &rk3288_ctrl_data,
        .win = rk3399_vop_lit_win_data,