.. | .. |
---|
35 | 35 | #include <linux/swab.h> |
---|
36 | 36 | #include <linux/sort.h> |
---|
37 | 37 | #include <linux/rockchip/cpu.h> |
---|
| 38 | +#include <linux/workqueue.h> |
---|
| 39 | +#include <linux/types.h> |
---|
38 | 40 | #include <soc/rockchip/rockchip_dmc.h> |
---|
39 | 41 | #include <soc/rockchip/rockchip-system-status.h> |
---|
40 | 42 | #include <uapi/linux/videodev2.h> |
---|
.. | .. |
---|
47 | 49 | #include "rockchip_drm_psr.h" |
---|
48 | 50 | #include "rockchip_drm_vop.h" |
---|
49 | 51 | #include "rockchip_vop_reg.h" |
---|
| 52 | +#include "rockchip_post_csc.h" |
---|
50 | 53 | |
---|
51 | 54 | #define _REG_SET(vop2, name, off, reg, mask, v, relaxed) \ |
---|
52 | 55 | vop2_mask_write(vop2, off + reg.offset, mask, reg.shift, v, reg.write_mask, relaxed) |
---|
.. | .. |
---|
78 | 81 | |
---|
79 | 82 | #define VOP_CTRL_SET(x, name, v) \ |
---|
80 | 83 | REG_SET(x, name, 0, (x)->data->ctrl->name, v, false) |
---|
| 84 | + |
---|
| 85 | +#define VOP_CTRL_GET(x, name) vop2_read_reg(x, 0, &(x)->data->ctrl->name) |
---|
81 | 86 | |
---|
82 | 87 | #define VOP_INTR_GET(vop2, name) \ |
---|
83 | 88 | vop2_read_reg(vop2, 0, &vop2->data->ctrl->name) |
---|
.. | .. |
---|
477 | 482 | uint8_t id; |
---|
478 | 483 | bool layer_sel_update; |
---|
479 | 484 | bool xmirror_en; |
---|
| 485 | + bool need_reset_p2i_flag; |
---|
| 486 | + atomic_t post_buf_empty_flag; |
---|
480 | 487 | const struct vop2_video_port_regs *regs; |
---|
481 | 488 | |
---|
482 | 489 | struct completion dsp_hold_completion; |
---|
.. | .. |
---|
555 | 562 | bool gamma_lut_active; |
---|
556 | 563 | |
---|
557 | 564 | /** |
---|
| 565 | + * @lut_dma_rid: lut dma id |
---|
| 566 | + */ |
---|
| 567 | + u16 lut_dma_rid; |
---|
| 568 | + |
---|
| 569 | + /** |
---|
558 | 570 | * @gamma_lut: atomic gamma look up table |
---|
559 | 571 | */ |
---|
560 | 572 | struct drm_color_lut *gamma_lut; |
---|
.. | .. |
---|
568 | 580 | * @cubic_lut_gem_obj: gem obj to store cubic lut |
---|
569 | 581 | */ |
---|
570 | 582 | struct rockchip_gem_object *cubic_lut_gem_obj; |
---|
| 583 | + |
---|
| 584 | + /** |
---|
| 585 | + * @hdr_lut_gem_obj: gem obj to store hdr lut |
---|
| 586 | + */ |
---|
| 587 | + struct rockchip_gem_object *hdr_lut_gem_obj; |
---|
571 | 588 | |
---|
572 | 589 | /** |
---|
573 | 590 | * @cubic_lut: cubic look up table |
---|
.. | .. |
---|
591 | 608 | struct drm_property *plane_mask_prop; |
---|
592 | 609 | |
---|
593 | 610 | /** |
---|
| 611 | + * @hdr_ext_data_prop: hdr extend data interaction with userspace |
---|
| 612 | + */ |
---|
| 613 | + struct drm_property *hdr_ext_data_prop; |
---|
| 614 | + |
---|
| 615 | + int hdrvivid_mode; |
---|
| 616 | + |
---|
| 617 | + /** |
---|
| 618 | + * @acm_lut_data_prop: acm lut data interaction with userspace |
---|
| 619 | + */ |
---|
| 620 | + struct drm_property *acm_lut_data_prop; |
---|
| 621 | + /** |
---|
| 622 | + * @post_csc_data_prop: post csc data interaction with userspace |
---|
| 623 | + */ |
---|
| 624 | + struct drm_property *post_csc_data_prop; |
---|
| 625 | + |
---|
| 626 | + /** |
---|
594 | 627 | * @primary_plane_phy_id: vp primary plane phy id, the primary plane |
---|
595 | 628 | * will be used to show uboot logo and kernel logo |
---|
596 | 629 | */ |
---|
597 | 630 | enum vop2_layer_phy_id primary_plane_phy_id; |
---|
| 631 | + |
---|
| 632 | + struct post_acm acm_info; |
---|
| 633 | + struct post_csc csc_info; |
---|
598 | 634 | }; |
---|
599 | 635 | |
---|
600 | 636 | struct vop2 { |
---|
.. | .. |
---|
652 | 688 | */ |
---|
653 | 689 | uint32_t registered_num_wins; |
---|
654 | 690 | uint8_t used_mixers; |
---|
| 691 | + uint8_t esmart_lb_mode; |
---|
655 | 692 | /** |
---|
656 | 693 | * @active_vp_mask: Bitmask of active video ports; |
---|
657 | 694 | */ |
---|
.. | .. |
---|
684 | 721 | unsigned int enable_count; |
---|
685 | 722 | struct clk *hclk; |
---|
686 | 723 | struct clk *aclk; |
---|
| 724 | + struct work_struct post_buf_empty_work; |
---|
| 725 | + struct workqueue_struct *workqueue; |
---|
687 | 726 | |
---|
688 | 727 | struct vop2_layer layers[ROCKCHIP_MAX_LAYER]; |
---|
689 | 728 | /* must put at the end of the struct */ |
---|
.. | .. |
---|
717 | 756 | { MEDIA_BUS_FMT_UYVY8_2X8, "UYVY8_2X8" }, |
---|
718 | 757 | { MEDIA_BUS_FMT_YUYV8_1X16, "YUYV8_1X16" }, |
---|
719 | 758 | { MEDIA_BUS_FMT_UYVY8_1X16, "UYVY8_1X16" }, |
---|
| 759 | + { MEDIA_BUS_FMT_RGB101010_1X30, "RGB101010_1x30" }, |
---|
720 | 760 | }; |
---|
721 | 761 | |
---|
722 | 762 | static DRM_ENUM_NAME_FN(drm_get_bus_format_name, drm_bus_format_enum_list) |
---|
.. | .. |
---|
991 | 1031 | static uint32_t vop2_read_vcnt(struct vop2_video_port *vp) |
---|
992 | 1032 | { |
---|
993 | 1033 | uint32_t offset = RK3568_SYS_STATUS0 + (vp->id << 2); |
---|
| 1034 | + uint32_t vcnt0, vcnt1; |
---|
| 1035 | + int i = 0; |
---|
994 | 1036 | |
---|
995 | | - return vop2_readl(vp->vop2, offset) >> 16; |
---|
| 1037 | + for (i = 0; i < 10; i++) { |
---|
| 1038 | + vcnt0 = vop2_readl(vp->vop2, offset) >> 16; |
---|
| 1039 | + vcnt1 = vop2_readl(vp->vop2, offset) >> 16; |
---|
| 1040 | + |
---|
| 1041 | + if ((vcnt1 - vcnt0) <= 1) |
---|
| 1042 | + break; |
---|
| 1043 | + } |
---|
| 1044 | + |
---|
| 1045 | + if (i == 10) { |
---|
| 1046 | + DRM_DEV_ERROR(vp->vop2->dev, "read VP%d vcnt error: %d %d\n", vp->id, vcnt0, vcnt1); |
---|
| 1047 | + vcnt1 = vop2_readl(vp->vop2, offset) >> 16; |
---|
| 1048 | + } |
---|
| 1049 | + |
---|
| 1050 | + return vcnt1; |
---|
996 | 1051 | } |
---|
997 | 1052 | |
---|
998 | 1053 | static void vop2_wait_for_irq_handler(struct drm_crtc *crtc) |
---|
.. | .. |
---|
1864 | 1919 | #define VOP2_COMMON_SCL_FAC_CHECK(src, dst, fac) \ |
---|
1865 | 1920 | (fac * (dst - 1) >> 16 < (src - 1)) |
---|
1866 | 1921 | #define VOP3_COMMON_HOR_SCL_FAC_CHECK(src, dst, fac) \ |
---|
1867 | | - (fac * (dst - 1) >> 16 <= (src - 1)) |
---|
| 1922 | + (fac * (dst - 1) >> 16 < (src - 1)) |
---|
1868 | 1923 | |
---|
1869 | 1924 | static uint16_t vop2_scale_factor(enum scale_mode mode, |
---|
1870 | 1925 | int32_t filter_mode, |
---|
.. | .. |
---|
1983 | 2038 | } |
---|
1984 | 2039 | } |
---|
1985 | 2040 | |
---|
1986 | | - if (src_h >= (4 * dst_h)) { |
---|
1987 | | - ygt4 = 1; |
---|
1988 | | - src_h >>= 2; |
---|
1989 | | - } else if (src_h >= (2 * dst_h)) { |
---|
1990 | | - ygt2 = 1; |
---|
1991 | | - src_h >>= 1; |
---|
| 2041 | + /** |
---|
| 2042 | + * The rk3528 is processed as 2 pixel/cycle, |
---|
| 2043 | + * so ygt2/ygt4 needs to be triggered in advance to improve performance |
---|
| 2044 | + * when src_w is bigger than 1920. |
---|
| 2045 | + * dst_h / src_h is at [1, 0.65) ygt2=0; ygt4=0; |
---|
| 2046 | + * dst_h / src_h is at [0.65, 0.35) ygt2=1; ygt4=0; |
---|
| 2047 | + * dst_h / src_h is at [0.35, 0) ygt2=0; ygt4=1; |
---|
| 2048 | + */ |
---|
| 2049 | + if (vop2->version == VOP_VERSION_RK3528 && src_w > 1920) { |
---|
| 2050 | + if (src_h >= (100 * dst_h / 35)) { |
---|
| 2051 | + ygt4 = 1; |
---|
| 2052 | + src_h >>= 2; |
---|
| 2053 | + } else if ((src_h >= 100 * dst_h / 65) && (src_h < 100 * dst_h / 35)) { |
---|
| 2054 | + ygt2 = 1; |
---|
| 2055 | + src_h >>= 1; |
---|
| 2056 | + } |
---|
| 2057 | + } else { |
---|
| 2058 | + if (src_h >= (4 * dst_h)) { |
---|
| 2059 | + ygt4 = 1; |
---|
| 2060 | + src_h >>= 2; |
---|
| 2061 | + } else if (src_h >= (2 * dst_h)) { |
---|
| 2062 | + ygt2 = 1; |
---|
| 2063 | + src_h >>= 1; |
---|
| 2064 | + } |
---|
1992 | 2065 | } |
---|
1993 | 2066 | |
---|
1994 | 2067 | yrgb_hor_scl_mode = scl_get_scl_mode(src_w, dst_w); |
---|
.. | .. |
---|
2065 | 2138 | if (!is_vop3(vop2) || |
---|
2066 | 2139 | (!vpstate->afbc_en && !vpstate->tiled_en) || |
---|
2067 | 2140 | win_data->vsd_pre_filter_mode == VOP3_PRE_SCALE_DOWN_GT) { |
---|
2068 | | - if (cbcr_src_h >= (4 * dst_h)) |
---|
2069 | | - ygt4 = 1; |
---|
2070 | | - else if (cbcr_src_h >= (2 * dst_h)) |
---|
2071 | | - ygt2 = 1; |
---|
| 2141 | + if (vop2->version == VOP_VERSION_RK3528 && src_w > 1920) { |
---|
| 2142 | + if (cbcr_src_h >= (100 * dst_h / 35)) |
---|
| 2143 | + ygt4 = 1; |
---|
| 2144 | + else if ((cbcr_src_h >= 100 * dst_h / 65) && (cbcr_src_h < 100 * dst_h / 35)) |
---|
| 2145 | + ygt2 = 1; |
---|
| 2146 | + } else { |
---|
| 2147 | + if (cbcr_src_h >= (4 * dst_h)) |
---|
| 2148 | + ygt4 = 1; |
---|
| 2149 | + else if (cbcr_src_h >= (2 * dst_h)) |
---|
| 2150 | + ygt2 = 1; |
---|
| 2151 | + } |
---|
2072 | 2152 | |
---|
2073 | 2153 | if (ygt4) |
---|
2074 | 2154 | cbcr_src_h >>= 2; |
---|
.. | .. |
---|
2230 | 2310 | vpstate->r2y_en = 0; |
---|
2231 | 2311 | vpstate->csc_mode = 0; |
---|
2232 | 2312 | |
---|
2233 | | - /* hdr2sdr and sdr2hdr will do csc itself */ |
---|
2234 | | - if (vpstate->hdr2sdr_en) { |
---|
2235 | | - /* |
---|
2236 | | - * This is hdr2sdr enabled plane |
---|
2237 | | - * If it's RGB layer do hdr2sdr, we need to do r2y before send to hdr2sdr, |
---|
2238 | | - * because hdr2sdr only support yuv input. |
---|
2239 | | - */ |
---|
2240 | | - if (!is_input_yuv) { |
---|
2241 | | - vpstate->r2y_en = 1; |
---|
2242 | | - vpstate->csc_mode = vop2_convert_csc_mode(output_csc, CSC_10BIT_DEPTH); |
---|
| 2313 | + if (is_vop3(vp->vop2)) { |
---|
| 2314 | + if (vpstate->hdr_in) { |
---|
| 2315 | + if (is_input_yuv) { |
---|
| 2316 | + vpstate->y2r_en = 1; |
---|
| 2317 | + vpstate->csc_mode = vop2_convert_csc_mode(input_csc, |
---|
| 2318 | + CSC_13BIT_DEPTH); |
---|
| 2319 | + } |
---|
| 2320 | + return; |
---|
| 2321 | + } else if (vp->sdr2hdr_en) { |
---|
| 2322 | + if (is_input_yuv) { |
---|
| 2323 | + vpstate->y2r_en = 1; |
---|
| 2324 | + vpstate->csc_mode = vop2_convert_csc_mode(input_csc, |
---|
| 2325 | + csc_y2r_bit_depth); |
---|
| 2326 | + } |
---|
| 2327 | + return; |
---|
2243 | 2328 | } |
---|
2244 | | - return; |
---|
2245 | | - } else if (!vpstate->hdr_in && vp->sdr2hdr_en) { |
---|
2246 | | - /* |
---|
2247 | | - * This is sdr2hdr enabled plane |
---|
2248 | | - * If it's YUV layer do sdr2hdr, we need to do y2r before send to sdr2hdr, |
---|
2249 | | - * because sdr2hdr only support rgb input. |
---|
2250 | | - */ |
---|
2251 | | - if (is_input_yuv) { |
---|
2252 | | - vpstate->y2r_en = 1; |
---|
2253 | | - vpstate->csc_mode = vop2_convert_csc_mode(input_csc, csc_y2r_bit_depth); |
---|
| 2329 | + } else { |
---|
| 2330 | + /* hdr2sdr and sdr2hdr will do csc itself */ |
---|
| 2331 | + if (vpstate->hdr2sdr_en) { |
---|
| 2332 | + /* |
---|
| 2333 | + * This is hdr2sdr enabled plane |
---|
| 2334 | + * If it's RGB layer do hdr2sdr, we need to do r2y before send to hdr2sdr, |
---|
| 2335 | + * because hdr2sdr only support yuv input. |
---|
| 2336 | + */ |
---|
| 2337 | + if (!is_input_yuv) { |
---|
| 2338 | + vpstate->r2y_en = 1; |
---|
| 2339 | + vpstate->csc_mode = vop2_convert_csc_mode(output_csc, |
---|
| 2340 | + CSC_10BIT_DEPTH); |
---|
| 2341 | + } |
---|
| 2342 | + return; |
---|
| 2343 | + } else if (!vpstate->hdr_in && vp->sdr2hdr_en) { |
---|
| 2344 | + /* |
---|
| 2345 | + * This is sdr2hdr enabled plane |
---|
| 2346 | + * If it's YUV layer do sdr2hdr, we need to do y2r before send to sdr2hdr, |
---|
| 2347 | + * because sdr2hdr only support rgb input. |
---|
| 2348 | + */ |
---|
| 2349 | + if (is_input_yuv) { |
---|
| 2350 | + vpstate->y2r_en = 1; |
---|
| 2351 | + vpstate->csc_mode = vop2_convert_csc_mode(input_csc, |
---|
| 2352 | + csc_y2r_bit_depth); |
---|
| 2353 | + } |
---|
| 2354 | + return; |
---|
2254 | 2355 | } |
---|
2255 | | - return; |
---|
2256 | 2356 | } |
---|
2257 | 2357 | |
---|
2258 | 2358 | if (is_input_yuv && !is_output_yuv) { |
---|
.. | .. |
---|
2657 | 2757 | fifo_throd = fb->pitches[0] >> 4; |
---|
2658 | 2758 | if (fifo_throd >= vop2->data->wb->fifo_depth) |
---|
2659 | 2759 | fifo_throd = vop2->data->wb->fifo_depth; |
---|
2660 | | - r2y = fb->format->is_yuv && (!is_yuv_output(vcstate->bus_format)); |
---|
| 2760 | + r2y = !vcstate->yuv_overlay && fb->format->is_yuv; |
---|
2661 | 2761 | |
---|
2662 | 2762 | /* |
---|
2663 | 2763 | * the vp_id register config done immediately |
---|
.. | .. |
---|
2963 | 3063 | */ |
---|
2964 | 3064 | static void vop3_layer_map_initial(struct vop2 *vop2, uint32_t current_vp_id) |
---|
2965 | 3065 | { |
---|
2966 | | - struct vop2_video_port *vp; |
---|
2967 | | - struct vop2_win *win; |
---|
2968 | | - unsigned long win_mask; |
---|
2969 | 3066 | uint16_t vp_id; |
---|
2970 | | - int phys_id; |
---|
2971 | | - int i; |
---|
| 3067 | + struct drm_plane *plane = NULL; |
---|
2972 | 3068 | |
---|
2973 | | - for (i = 0; i < vop2->data->nr_vps; i++) { |
---|
2974 | | - vp_id = i; |
---|
2975 | | - vp = &vop2->vps[vp_id]; |
---|
2976 | | - vp->win_mask = vp->plane_mask; |
---|
2977 | | - win_mask = vp->win_mask; |
---|
2978 | | - for_each_set_bit(phys_id, &win_mask, ROCKCHIP_MAX_LAYER) { |
---|
2979 | | - win = vop2_find_win_by_phys_id(vop2, phys_id); |
---|
2980 | | - VOP_CTRL_SET(vop2, win_vp_id[phys_id], vp_id); |
---|
2981 | | - win->vp_mask = BIT(vp_id); |
---|
2982 | | - win->old_vp_mask = win->vp_mask; |
---|
2983 | | - DRM_DEV_DEBUG(vop2->dev, "%s attach to vp%d\n", win->name, vp_id); |
---|
2984 | | - } |
---|
| 3069 | + drm_for_each_plane(plane, vop2->drm_dev) { |
---|
| 3070 | + struct vop2_win *win = to_vop2_win(plane); |
---|
| 3071 | + |
---|
| 3072 | + vp_id = VOP_CTRL_GET(vop2, win_vp_id[win->phys_id]); |
---|
| 3073 | + win->vp_mask = BIT(vp_id); |
---|
| 3074 | + win->old_vp_mask = win->vp_mask; |
---|
| 3075 | + vop2->vps[vp_id].win_mask |= BIT(win->phys_id); |
---|
2985 | 3076 | } |
---|
2986 | 3077 | } |
---|
2987 | 3078 | |
---|
.. | .. |
---|
3081 | 3172 | VOP_MODULE_SET(vop2, wb, axi_uv_id, 0xe); |
---|
3082 | 3173 | vop2_wb_cfg_done(vp); |
---|
3083 | 3174 | |
---|
3084 | | - if (is_vop3(vop2)) |
---|
3085 | | - VOP_CTRL_SET(vop2, esmart_lb_mode, vop2->data->esmart_lb_mode); |
---|
| 3175 | + if (is_vop3(vop2)) { |
---|
| 3176 | + VOP_CTRL_SET(vop2, dsp_vs_t_sel, 0); |
---|
| 3177 | + VOP_CTRL_SET(vop2, esmart_lb_mode, vop2->esmart_lb_mode); |
---|
| 3178 | + } |
---|
| 3179 | + |
---|
| 3180 | + /* |
---|
| 3181 | + * This is unused and error init value for rk3528 vp1, if less of this config, |
---|
| 3182 | + * vp1 can't display normally. |
---|
| 3183 | + */ |
---|
| 3184 | + if (vop2->version == VOP_VERSION_RK3528) |
---|
| 3185 | + vop2_mask_write(vop2, 0x700, 0x3, 4, 0, 0, true); |
---|
3086 | 3186 | |
---|
3087 | 3187 | VOP_CTRL_SET(vop2, cfg_done_en, 1); |
---|
3088 | 3188 | /* |
---|
.. | .. |
---|
3151 | 3251 | { |
---|
3152 | 3252 | struct vop2_video_port *vp = to_vop2_video_port(crtc); |
---|
3153 | 3253 | struct vop2 *vop2 = vp->vop2; |
---|
| 3254 | + const struct vop2_video_port_data *vp_data = &vop2->data->vp[vp->id]; |
---|
3154 | 3255 | int ret; |
---|
3155 | 3256 | |
---|
3156 | 3257 | WARN_ON(vp->event); |
---|
.. | .. |
---|
3163 | 3264 | VOP_MODULE_SET(vop2, vp, cubic_lut_en, 0); |
---|
3164 | 3265 | } |
---|
3165 | 3266 | |
---|
| 3267 | + if (vp_data->feature & VOP_FEATURE_VIVID_HDR) |
---|
| 3268 | + VOP_MODULE_SET(vop2, vp, hdr_lut_update_en, 0); |
---|
3166 | 3269 | vop2_disable_all_planes_for_crtc(crtc); |
---|
3167 | 3270 | |
---|
3168 | 3271 | /* |
---|
.. | .. |
---|
3188 | 3291 | vop2_dsp_hold_valid_irq_disable(crtc); |
---|
3189 | 3292 | |
---|
3190 | 3293 | vop2_disable(crtc); |
---|
| 3294 | + memset(&vp->active_tv_state, 0, sizeof(vp->active_tv_state)); |
---|
3191 | 3295 | vop2_unlock(vop2); |
---|
3192 | 3296 | |
---|
3193 | 3297 | vop2->active_vp_mask &= ~BIT(vp->id); |
---|
.. | .. |
---|
3500 | 3604 | uint32_t actual_w, actual_h, dsp_w, dsp_h; |
---|
3501 | 3605 | uint32_t dsp_stx, dsp_sty; |
---|
3502 | 3606 | uint32_t act_info, dsp_info, dsp_st; |
---|
3503 | | - uint32_t format; |
---|
| 3607 | + uint32_t format, check_size; |
---|
3504 | 3608 | uint32_t afbc_format; |
---|
3505 | 3609 | uint32_t rb_swap; |
---|
3506 | 3610 | uint32_t uv_swap; |
---|
.. | .. |
---|
3569 | 3673 | actual_w = drm_rect_width(src) >> 16; |
---|
3570 | 3674 | actual_h = drm_rect_height(src) >> 16; |
---|
3571 | 3675 | dsp_w = drm_rect_width(dest); |
---|
3572 | | - if (dest->x1 + dsp_w > adjusted_mode->hdisplay) { |
---|
| 3676 | + if (dest->x1 + dsp_w > adjusted_mode->crtc_hdisplay) { |
---|
3573 | 3677 | DRM_ERROR("vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n", |
---|
3574 | | - vp->id, win->name, dest->x1, dsp_w, adjusted_mode->hdisplay); |
---|
| 3678 | + vp->id, win->name, dest->x1, dsp_w, adjusted_mode->crtc_hdisplay); |
---|
3575 | 3679 | dsp_w = adjusted_mode->hdisplay - dest->x1; |
---|
3576 | 3680 | if (dsp_w < 4) |
---|
3577 | 3681 | dsp_w = 4; |
---|
3578 | 3682 | actual_w = dsp_w * actual_w / drm_rect_width(dest); |
---|
3579 | 3683 | } |
---|
3580 | 3684 | dsp_h = drm_rect_height(dest); |
---|
3581 | | - if (dest->y1 + dsp_h > adjusted_mode->vdisplay) { |
---|
| 3685 | + check_size = adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE ? adjusted_mode->vdisplay : adjusted_mode->crtc_vdisplay; |
---|
| 3686 | + if (dest->y1 + dsp_h > check_size) { |
---|
3582 | 3687 | DRM_ERROR("vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n", |
---|
3583 | | - vp->id, win->name, dest->y1, dsp_h, adjusted_mode->vdisplay); |
---|
| 3688 | + vp->id, win->name, dest->y1, dsp_h, adjusted_mode->crtc_vdisplay); |
---|
3584 | 3689 | dsp_h = adjusted_mode->vdisplay - dest->y1; |
---|
3585 | 3690 | if (dsp_h < 4) |
---|
3586 | 3691 | dsp_h = 4; |
---|
.. | .. |
---|
3588 | 3693 | } |
---|
3589 | 3694 | |
---|
3590 | 3695 | /* |
---|
3591 | | - * This is workaround solution for IC design: |
---|
3592 | | - * esmart can't support scale down when actual_w % 16 == 1. |
---|
| 3696 | + * Workaround only for rk3568 vop |
---|
3593 | 3697 | */ |
---|
3594 | | - if (!(win->feature & WIN_FEATURE_AFBDC)) { |
---|
3595 | | - if (actual_w > dsp_w && (actual_w & 0xf) == 1) { |
---|
3596 | | - DRM_WARN("vp%d %s act_w[%d] MODE 16 == 1\n", vp->id, win->name, actual_w); |
---|
3597 | | - actual_w -= 1; |
---|
| 3698 | + if (vop2->version == VOP_VERSION_RK3568) { |
---|
| 3699 | + /* |
---|
| 3700 | + * This is workaround solution for IC design: |
---|
| 3701 | + * esmart can't support scale down when actual_w % 16 == 1. |
---|
| 3702 | + */ |
---|
| 3703 | + if (!(win->feature & WIN_FEATURE_AFBDC)) { |
---|
| 3704 | + if (actual_w > dsp_w && (actual_w & 0xf) == 1) { |
---|
| 3705 | + DRM_WARN("vp%d %s act_w[%d] MODE 16 == 1\n", vp->id, win->name, actual_w); |
---|
| 3706 | + actual_w -= 1; |
---|
| 3707 | + } |
---|
3598 | 3708 | } |
---|
3599 | | - } |
---|
3600 | 3709 | |
---|
3601 | | - if (vpstate->afbc_en && actual_w % 4) { |
---|
3602 | | - DRM_ERROR("vp%d %s actual_w[%d] should align as 4 pixel when enable afbc\n", |
---|
3603 | | - vp->id, win->name, actual_w); |
---|
3604 | | - actual_w = ALIGN_DOWN(actual_w, 4); |
---|
| 3710 | + if (vpstate->afbc_en && actual_w % 4) { |
---|
| 3711 | + DRM_ERROR("vp%d %s actual_w[%d] should align as 4 pixel when enable afbc\n", |
---|
| 3712 | + vp->id, win->name, actual_w); |
---|
| 3713 | + actual_w = ALIGN_DOWN(actual_w, 4); |
---|
| 3714 | + } |
---|
3605 | 3715 | } |
---|
3606 | 3716 | |
---|
3607 | 3717 | act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff); |
---|
.. | .. |
---|
3633 | 3743 | if (vop2->version != VOP_VERSION_RK3568) |
---|
3634 | 3744 | rk3588_vop2_win_cfg_axi(win); |
---|
3635 | 3745 | |
---|
3636 | | - if (is_vop3(vop2) && !vop2_cluster_window(win)) |
---|
| 3746 | + if (is_vop3(vop2) && !vop2_cluster_window(win) && !win->parent) |
---|
3637 | 3747 | VOP_WIN_SET(vop2, win, scale_engine_num, win->scale_engine_num); |
---|
3638 | 3748 | |
---|
3639 | 3749 | if (vpstate->afbc_en) { |
---|
.. | .. |
---|
3765 | 3875 | if (vop2_cluster_window(win)) { |
---|
3766 | 3876 | lb_mode = vop2_get_cluster_lb_mode(win, vpstate); |
---|
3767 | 3877 | VOP_CLUSTER_SET(vop2, win, lb_mode, lb_mode); |
---|
| 3878 | + VOP_CLUSTER_SET(vop2, win, scl_lb_mode, lb_mode == 1 ? 3 : 0); |
---|
3768 | 3879 | VOP_CLUSTER_SET(vop2, win, enable, 1); |
---|
| 3880 | + VOP_CLUSTER_SET(vop2, win, frm_reset_en, 1); |
---|
3769 | 3881 | } |
---|
3770 | 3882 | if (vcstate->output_if & VOP_OUTPUT_IF_BT1120 || |
---|
3771 | 3883 | vcstate->output_if & VOP_OUTPUT_IF_BT656) |
---|
.. | .. |
---|
4736 | 4848 | struct drm_display_mode *adj_mode) |
---|
4737 | 4849 | { |
---|
4738 | 4850 | struct vop2_video_port *vp = to_vop2_video_port(crtc); |
---|
| 4851 | + struct vop2 *vop2 = vp->vop2; |
---|
| 4852 | + |
---|
| 4853 | + /* |
---|
| 4854 | + * For RK3568 and RK3588, the hactive of video timing must |
---|
| 4855 | + * be 4-pixel aligned. |
---|
| 4856 | + */ |
---|
| 4857 | + if (vop2->version == VOP_VERSION_RK3568 || vop2->version == VOP_VERSION_RK3588) { |
---|
| 4858 | + if (adj_mode->hdisplay % 4) { |
---|
| 4859 | + u16 old_hdisplay = adj_mode->hdisplay; |
---|
| 4860 | + u16 align; |
---|
| 4861 | + |
---|
| 4862 | + align = 4 - (adj_mode->hdisplay % 4); |
---|
| 4863 | + adj_mode->hdisplay += align; |
---|
| 4864 | + adj_mode->hsync_start += align; |
---|
| 4865 | + adj_mode->hsync_end += align; |
---|
| 4866 | + adj_mode->htotal += align; |
---|
| 4867 | + |
---|
| 4868 | + DRM_WARN("VP%d: hactive need to be aligned with 4-pixel, %d -> %d\n", |
---|
| 4869 | + vp->id, old_hdisplay, adj_mode->hdisplay); |
---|
| 4870 | + } |
---|
| 4871 | + } |
---|
4739 | 4872 | |
---|
4740 | 4873 | drm_mode_set_crtcinfo(adj_mode, CRTC_INTERLACE_HALVE_V | CRTC_STEREO_DOUBLE); |
---|
4741 | 4874 | |
---|
.. | .. |
---|
4799 | 4932 | to_rockchip_crtc_state(crtc->state); |
---|
4800 | 4933 | struct vop2_video_port *vp = to_vop2_video_port(crtc); |
---|
4801 | 4934 | struct vop2 *vop2 = vp->vop2; |
---|
| 4935 | + const struct vop2_data *vop2_data = vop2->data; |
---|
| 4936 | + const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; |
---|
4802 | 4937 | struct drm_display_mode *mode = &crtc->state->adjusted_mode; |
---|
4803 | 4938 | u16 vtotal = mode->crtc_vtotal; |
---|
4804 | 4939 | u16 hdisplay = mode->crtc_hdisplay; |
---|
.. | .. |
---|
4838 | 4973 | val = vact_st_f1 << 16 | vact_end_f1; |
---|
4839 | 4974 | VOP_MODULE_SET(vop2, vp, vpost_st_end_f1, val); |
---|
4840 | 4975 | } |
---|
4841 | | - VOP_MODULE_SET(vop2, vp, post_dsp_out_r2y, |
---|
4842 | | - is_yuv_output(vcstate->bus_format)); |
---|
| 4976 | + |
---|
| 4977 | + /* |
---|
| 4978 | + * BCSH[R2Y] -> POST Linebuffer[post scale] -> the background R2Y will be deal by post_dsp_out_r2y |
---|
| 4979 | + * |
---|
| 4980 | + * POST Linebuffer[post scale] -> ACM[R2Y] -> the background R2Y will be deal by ACM[R2Y] |
---|
| 4981 | + */ |
---|
| 4982 | + if (vp_data->feature & VOP_FEATURE_POST_ACM) |
---|
| 4983 | + VOP_MODULE_SET(vop2, vp, post_dsp_out_r2y, vcstate->yuv_overlay); |
---|
| 4984 | + else |
---|
| 4985 | + VOP_MODULE_SET(vop2, vp, post_dsp_out_r2y, is_yuv_output(vcstate->bus_format)); |
---|
4843 | 4986 | } |
---|
4844 | 4987 | |
---|
4845 | 4988 | /* |
---|
.. | .. |
---|
4880 | 5023 | return false; |
---|
4881 | 5024 | } |
---|
4882 | 5025 | |
---|
| 5026 | +/* |
---|
| 5027 | + * For vop3 video port0, if hdr_vivid is not enable, the pipe delay time as follow: |
---|
| 5028 | + * win_dly + config_win_dly + layer_mix_dly + sdr2hdr_dly + * hdr_mix_dly = config_bg_dly |
---|
| 5029 | + * |
---|
| 5030 | + * if hdr_vivid is enable, the hdr layer's pipe delay time as follow: |
---|
| 5031 | + * win_dly + config_win_dly +hdrvivid_dly + hdr_mix_dly = config_bg_dly |
---|
| 5032 | + * |
---|
| 5033 | + * If hdrvivid and sdr2hdr bot enable, the time arrivr hdr_mix should be the same: |
---|
| 5034 | + * win_dly + config_win_dly0 + hdrvivid_dly = win_dly + config_win_dly1 + laer_mix_dly + |
---|
| 5035 | + * sdr2hdr_dly |
---|
| 5036 | + * |
---|
| 5037 | + * For vop3 video port1, the pipe delay time as follow: |
---|
| 5038 | + * win_dly + config_win_dly + layer_mix_dly = config_bg_dly |
---|
| 5039 | + * |
---|
| 5040 | + * Here, win_dly, layer_mix_dly, sdr2hdr_dly, hdr_mix_dly, hdrvivid_dly is the hardware |
---|
| 5041 | + * delay cycles. Config_win_dly and config_bg_dly is the register value that we can config. |
---|
| 5042 | + * Different hdr vivid mode have different hdrvivid_dly. For sdr2hdr_dly, only sde2hdr |
---|
| 5043 | + * enable, it will delay, otherwise, the sdr2hdr_dly is 0. |
---|
| 5044 | + * |
---|
| 5045 | + * For default, the config_win_dly will be 0, it just user to make the pipe to arrive |
---|
| 5046 | + * hdr_mix at the same time. |
---|
| 5047 | + */ |
---|
| 5048 | +static void vop3_setup_pipe_dly(struct vop2_video_port *vp, const struct vop2_zpos *vop2_zpos) |
---|
| 5049 | +{ |
---|
| 5050 | + struct vop2 *vop2 = vp->vop2; |
---|
| 5051 | + struct drm_crtc *crtc = &vp->crtc; |
---|
| 5052 | + const struct vop2_zpos *zpos; |
---|
| 5053 | + struct drm_plane *plane; |
---|
| 5054 | + struct vop2_plane_state *vpstate; |
---|
| 5055 | + struct vop2_win *win; |
---|
| 5056 | + const struct vop2_data *vop2_data = vop2->data; |
---|
| 5057 | + const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; |
---|
| 5058 | + struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; |
---|
| 5059 | + u16 hsync_len = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; |
---|
| 5060 | + u16 hdisplay = adjusted_mode->crtc_hdisplay; |
---|
| 5061 | + int bg_dly = 0x0; |
---|
| 5062 | + int dly = 0x0; |
---|
| 5063 | + int hdr_win_dly; |
---|
| 5064 | + int sdr_win_dly; |
---|
| 5065 | + int sdr2hdr_dly; |
---|
| 5066 | + int pre_scan_dly; |
---|
| 5067 | + int i; |
---|
| 5068 | + |
---|
| 5069 | + /** |
---|
| 5070 | + * config bg dly, select the max delay num of hdrvivid and sdr2hdr module |
---|
| 5071 | + * as the increase value of bg delay num. If hdrvivid and sdr2hdr is not |
---|
| 5072 | + * work, the default bg_dly is 0x10. and the default win delay num is 0. |
---|
| 5073 | + */ |
---|
| 5074 | + if ((vp->hdr_en || vp->sdr2hdr_en) && |
---|
| 5075 | + (vp->hdrvivid_mode >= 0 && vp->hdrvivid_mode <= SDR2HLG)) { |
---|
| 5076 | + /* set sdr2hdr_dly to 0 if sdr2hdr is disable */ |
---|
| 5077 | + sdr2hdr_dly = vp->sdr2hdr_en ? vp_data->sdr2hdr_dly : 0; |
---|
| 5078 | + |
---|
| 5079 | + /* set the max delay pipe's config_win_dly as 0 */ |
---|
| 5080 | + if (vp_data->hdrvivid_dly[vp->hdrvivid_mode] >= |
---|
| 5081 | + sdr2hdr_dly + vp_data->layer_mix_dly) { |
---|
| 5082 | + bg_dly = vp_data->win_dly + vp_data->hdrvivid_dly[vp->hdrvivid_mode] + |
---|
| 5083 | + vp_data->hdr_mix_dly; |
---|
| 5084 | + hdr_win_dly = 0; |
---|
| 5085 | + sdr_win_dly = vp_data->hdrvivid_dly[vp->hdrvivid_mode] - |
---|
| 5086 | + vp_data->layer_mix_dly - sdr2hdr_dly; |
---|
| 5087 | + } else { |
---|
| 5088 | + bg_dly = vp_data->win_dly + vp_data->layer_mix_dly + sdr2hdr_dly + |
---|
| 5089 | + vp_data->hdr_mix_dly; |
---|
| 5090 | + hdr_win_dly = sdr2hdr_dly + vp_data->layer_mix_dly - |
---|
| 5091 | + vp_data->hdrvivid_dly[vp->hdrvivid_mode]; |
---|
| 5092 | + sdr_win_dly = 0; |
---|
| 5093 | + } |
---|
| 5094 | + } else { |
---|
| 5095 | + bg_dly = vp_data->win_dly + vp_data->layer_mix_dly + vp_data->hdr_mix_dly; |
---|
| 5096 | + sdr_win_dly = 0; |
---|
| 5097 | + } |
---|
| 5098 | + |
---|
| 5099 | + pre_scan_dly = bg_dly + (hdisplay >> 1) - 1; |
---|
| 5100 | + pre_scan_dly = (pre_scan_dly << 16) | hsync_len; |
---|
| 5101 | + VOP_MODULE_SET(vop2, vp, bg_dly, bg_dly); |
---|
| 5102 | + VOP_MODULE_SET(vop2, vp, pre_scan_htiming, pre_scan_dly); |
---|
| 5103 | + |
---|
| 5104 | + /** |
---|
| 5105 | + * config win dly |
---|
| 5106 | + */ |
---|
| 5107 | + if (!vop2_zpos) |
---|
| 5108 | + return; |
---|
| 5109 | + |
---|
| 5110 | + for (i = 0; i < vp->nr_layers; i++) { |
---|
| 5111 | + zpos = &vop2_zpos[i]; |
---|
| 5112 | + win = vop2_find_win_by_phys_id(vop2, zpos->win_phys_id); |
---|
| 5113 | + plane = &win->base; |
---|
| 5114 | + vpstate = to_vop2_plane_state(plane->state); |
---|
| 5115 | + |
---|
| 5116 | + if ((vp->hdr_en || vp->sdr2hdr_en) && |
---|
| 5117 | + (vp->hdrvivid_mode >= 0 && vp->hdrvivid_mode <= SDR2HLG)) { |
---|
| 5118 | + dly = vpstate->hdr_in ? hdr_win_dly : sdr_win_dly; |
---|
| 5119 | + } |
---|
| 5120 | + if (vop2_cluster_window(win)) |
---|
| 5121 | + dly |= dly << 8; |
---|
| 5122 | + |
---|
| 5123 | + VOP_CTRL_SET(vop2, win_dly[win->phys_id], dly); |
---|
| 5124 | + } |
---|
| 5125 | +} |
---|
| 5126 | + |
---|
4883 | 5127 | static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) |
---|
4884 | 5128 | { |
---|
4885 | 5129 | struct vop2_video_port *vp = to_vop2_video_port(crtc); |
---|
.. | .. |
---|
4900 | 5144 | u16 vact_st = adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vsync_start; |
---|
4901 | 5145 | u16 vact_end = vact_st + vdisplay; |
---|
4902 | 5146 | bool interlaced = !!(adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE); |
---|
4903 | | - uint8_t out_mode; |
---|
4904 | 5147 | bool dclk_inv, yc_swap = false; |
---|
4905 | 5148 | int act_end; |
---|
4906 | 5149 | uint32_t val; |
---|
.. | .. |
---|
4925 | 5168 | if (vcstate->output_if & VOP_OUTPUT_IF_RGB) { |
---|
4926 | 5169 | VOP_CTRL_SET(vop2, rgb_en, 1); |
---|
4927 | 5170 | VOP_CTRL_SET(vop2, rgb_mux, vp_data->id); |
---|
| 5171 | + VOP_CTRL_SET(vop2, rgb_pin_pol, val); |
---|
4928 | 5172 | VOP_GRF_SET(vop2, grf_dclk_inv, dclk_inv); |
---|
4929 | 5173 | } |
---|
4930 | 5174 | |
---|
.. | .. |
---|
5038 | 5282 | VOP_CTRL_SET(vop2, hdmi_dclk_pol, 1); |
---|
5039 | 5283 | } |
---|
5040 | 5284 | |
---|
5041 | | - if ((vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA && |
---|
5042 | | - !(vp_data->feature & VOP_FEATURE_OUTPUT_10BIT)) || |
---|
5043 | | - vcstate->output_if & VOP_OUTPUT_IF_BT656) |
---|
5044 | | - out_mode = ROCKCHIP_OUT_MODE_P888; |
---|
5045 | | - else |
---|
5046 | | - out_mode = vcstate->output_mode; |
---|
5047 | | - VOP_MODULE_SET(vop2, vp, out_mode, out_mode); |
---|
5048 | | - |
---|
5049 | | - if (vop2_output_uv_swap(vcstate->bus_format, vcstate->output_mode)) |
---|
5050 | | - VOP_MODULE_SET(vop2, vp, dsp_data_swap, DSP_RB_SWAP); |
---|
5051 | | - else |
---|
5052 | | - VOP_MODULE_SET(vop2, vp, dsp_data_swap, 0); |
---|
5053 | | - |
---|
5054 | | - vop2_dither_setup(crtc); |
---|
5055 | | - |
---|
5056 | 5285 | VOP_MODULE_SET(vop2, vp, htotal_pw, (htotal << 16) | hsync_len); |
---|
5057 | 5286 | val = hact_st << 16; |
---|
5058 | 5287 | val |= hact_end; |
---|
.. | .. |
---|
5105 | 5334 | VOP_MODULE_SET(vop2, vp, dclk_div2_phase_lock, 0); |
---|
5106 | 5335 | } |
---|
5107 | 5336 | |
---|
5108 | | - clk_set_rate(vp->dclk, adjusted_mode->crtc_clock * 1000); |
---|
| 5337 | + /* |
---|
| 5338 | + * For RK3528, the path of CVBS output is like: |
---|
| 5339 | + * VOP BT656 ENCODER -> CVBS BT656 DECODER -> CVBS ENCODER -> CVBS VDAC |
---|
| 5340 | + * The vop2 dclk should be four times crtc_clock for CVBS sampling clock needs. |
---|
| 5341 | + */ |
---|
| 5342 | + if (vop2->version == VOP_VERSION_RK3528 && vcstate->output_if & VOP_OUTPUT_IF_BT656) |
---|
| 5343 | + clk_set_rate(vp->dclk, 4 * adjusted_mode->crtc_clock * 1000); |
---|
| 5344 | + else |
---|
| 5345 | + clk_set_rate(vp->dclk, adjusted_mode->crtc_clock * 1000); |
---|
5109 | 5346 | |
---|
5110 | 5347 | vop2_post_config(crtc); |
---|
| 5348 | + |
---|
| 5349 | + if (is_vop3(vop2)) |
---|
| 5350 | + vop3_setup_pipe_dly(vp, NULL); |
---|
5111 | 5351 | |
---|
5112 | 5352 | vop2_cfg_done(crtc); |
---|
5113 | 5353 | |
---|
.. | .. |
---|
5154 | 5394 | struct drm_crtc_state *crtc_state) |
---|
5155 | 5395 | { |
---|
5156 | 5396 | return 0; |
---|
| 5397 | +} |
---|
| 5398 | + |
---|
| 5399 | +static void vop3_disable_dynamic_hdr(struct vop2_video_port *vp, uint8_t win_phys_id) |
---|
| 5400 | +{ |
---|
| 5401 | + struct vop2 *vop2 = vp->vop2; |
---|
| 5402 | + struct vop2_win *win = vop2_find_win_by_phys_id(vop2, win_phys_id); |
---|
| 5403 | + struct drm_plane *plane = &win->base; |
---|
| 5404 | + struct drm_plane_state *pstate = plane->state; |
---|
| 5405 | + struct vop2_plane_state *vpstate = to_vop2_plane_state(pstate); |
---|
| 5406 | + |
---|
| 5407 | + VOP_MODULE_SET(vop2, vp, hdr10_en, 0); |
---|
| 5408 | + VOP_MODULE_SET(vop2, vp, hdr_vivid_en, 0); |
---|
| 5409 | + VOP_MODULE_SET(vop2, vp, hdr_vivid_bypass_en, 0); |
---|
| 5410 | + VOP_MODULE_SET(vop2, vp, hdr_lut_update_en, 0); |
---|
| 5411 | + VOP_MODULE_SET(vop2, vp, sdr2hdr_en, 0); |
---|
| 5412 | + VOP_MODULE_SET(vop2, vp, sdr2hdr_path_en, 0); |
---|
| 5413 | + VOP_MODULE_SET(vop2, vp, sdr2hdr_auto_gating_en, 1); |
---|
| 5414 | + |
---|
| 5415 | + vp->hdr_en = false; |
---|
| 5416 | + vp->hdr_in = false; |
---|
| 5417 | + vp->hdr_out = false; |
---|
| 5418 | + vp->sdr2hdr_en = false; |
---|
| 5419 | + vpstate->hdr_in = false; |
---|
| 5420 | + vpstate->hdr2sdr_en = false; |
---|
| 5421 | +} |
---|
| 5422 | + |
---|
| 5423 | +static void vop3_setup_hdrvivid(struct vop2_video_port *vp, uint8_t win_phys_id) |
---|
| 5424 | +{ |
---|
| 5425 | + struct vop2 *vop2 = vp->vop2; |
---|
| 5426 | + struct vop2_win *win = vop2_find_win_by_phys_id(vop2, win_phys_id); |
---|
| 5427 | + struct drm_plane *plane = &win->base; |
---|
| 5428 | + struct drm_plane_state *pstate = plane->state; |
---|
| 5429 | + struct vop2_plane_state *vpstate = to_vop2_plane_state(pstate); |
---|
| 5430 | + struct drm_crtc_state *cstate = vp->crtc.state; |
---|
| 5431 | + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(cstate); |
---|
| 5432 | + unsigned long win_mask = vp->win_mask; |
---|
| 5433 | + int phys_id; |
---|
| 5434 | + struct hdrvivid_regs *hdrvivid_data; |
---|
| 5435 | + struct hdr_extend *hdr_data; |
---|
| 5436 | + bool have_sdr_layer = false; |
---|
| 5437 | + uint32_t hdr_mode; |
---|
| 5438 | + int i; |
---|
| 5439 | + u32 *tone_lut_kvaddr; |
---|
| 5440 | + dma_addr_t tone_lut_mst; |
---|
| 5441 | + |
---|
| 5442 | + vp->hdr_en = false; |
---|
| 5443 | + vp->hdr_in = false; |
---|
| 5444 | + vp->hdr_out = false; |
---|
| 5445 | + vp->sdr2hdr_en = false; |
---|
| 5446 | + vpstate->hdr_in = false; |
---|
| 5447 | + vpstate->hdr2sdr_en = false; |
---|
| 5448 | + |
---|
| 5449 | + hdr_data = (struct hdr_extend *)vcstate->hdr_ext_data->data; |
---|
| 5450 | + hdrvivid_data = &hdr_data->hdrvivid_data; |
---|
| 5451 | + |
---|
| 5452 | + hdr_mode = hdrvivid_data->hdr_mode; |
---|
| 5453 | + |
---|
| 5454 | + if (hdr_mode > SDR2HLG && hdr_mode != SDR2HDR10_USERSPACE && |
---|
| 5455 | + hdr_mode != SDR2HLG_USERSPACE) { |
---|
| 5456 | + DRM_ERROR("Invalid HDR mode:%d, beyond the mode range\n", hdr_mode); |
---|
| 5457 | + return; |
---|
| 5458 | + } |
---|
| 5459 | + |
---|
| 5460 | + /* adjust userspace hdr mode value to kernel value */ |
---|
| 5461 | + if (hdr_mode == SDR2HDR10_USERSPACE) |
---|
| 5462 | + hdr_mode = SDR2HDR10; |
---|
| 5463 | + if (hdr_mode == SDR2HLG_USERSPACE) |
---|
| 5464 | + hdr_mode = SDR2HLG; |
---|
| 5465 | + |
---|
| 5466 | + if (hdr_mode <= HDR102SDR && vpstate->eotf != SMPTE_ST2084 && vpstate->eotf != HLG) { |
---|
| 5467 | + DRM_ERROR("Invalid HDR mode:%d, mismatch plane eotf:%d\n", hdr_mode, |
---|
| 5468 | + vpstate->eotf); |
---|
| 5469 | + return; |
---|
| 5470 | + } |
---|
| 5471 | + |
---|
| 5472 | + vp->hdrvivid_mode = hdr_mode; |
---|
| 5473 | + vcstate->yuv_overlay = false; |
---|
| 5474 | + |
---|
| 5475 | + if (hdr_mode <= HDR102SDR) { |
---|
| 5476 | + vp->hdr_en = true; |
---|
| 5477 | + vp->hdr_in = true; |
---|
| 5478 | + vpstate->hdr_in = true; |
---|
| 5479 | + } else { |
---|
| 5480 | + vp->sdr2hdr_en = true; |
---|
| 5481 | + } |
---|
| 5482 | + |
---|
| 5483 | + /* |
---|
| 5484 | + * To confirm whether need to enable sdr2hdr. |
---|
| 5485 | + */ |
---|
| 5486 | + for_each_set_bit(phys_id, &win_mask, ROCKCHIP_MAX_LAYER) { |
---|
| 5487 | + win = vop2_find_win_by_phys_id(vop2, phys_id); |
---|
| 5488 | + plane = &win->base; |
---|
| 5489 | + pstate = plane->state; |
---|
| 5490 | + vpstate = to_vop2_plane_state(pstate); |
---|
| 5491 | + |
---|
| 5492 | + /* skip inactive plane */ |
---|
| 5493 | + if (!vop2_plane_active(pstate)) |
---|
| 5494 | + continue; |
---|
| 5495 | + |
---|
| 5496 | + if (vpstate->eotf != SMPTE_ST2084 && vpstate->eotf != HLG) { |
---|
| 5497 | + have_sdr_layer = true; |
---|
| 5498 | + break; |
---|
| 5499 | + } |
---|
| 5500 | + } |
---|
| 5501 | + |
---|
| 5502 | + if (hdr_mode == PQHDR2SDR_WITH_DYNAMIC || hdr_mode == HLG2SDR_WITH_DYNAMIC || |
---|
| 5503 | + hdr_mode == HLG2SDR_WITHOUT_DYNAMIC || hdr_mode == HDR102SDR) { |
---|
| 5504 | + vpstate->hdr2sdr_en = true; |
---|
| 5505 | + } else { |
---|
| 5506 | + vp->hdr_out = true; |
---|
| 5507 | + if (have_sdr_layer) |
---|
| 5508 | + vp->sdr2hdr_en = true; |
---|
| 5509 | + } |
---|
| 5510 | + |
---|
| 5511 | + /** |
---|
| 5512 | + * Config hdr ctrl registers |
---|
| 5513 | + */ |
---|
| 5514 | + vop2_writel(vop2, RK3528_SDR2HDR_CTRL, hdrvivid_data->sdr2hdr_ctrl); |
---|
| 5515 | + vop2_writel(vop2, RK3528_HDRVIVID_CTRL, hdrvivid_data->hdrvivid_ctrl); |
---|
| 5516 | + |
---|
| 5517 | + VOP_MODULE_SET(vop2, vp, hdr10_en, vp->hdr_en); |
---|
| 5518 | + if (vp->hdr_en) { |
---|
| 5519 | + VOP_MODULE_SET(vop2, vp, hdr_vivid_en, (hdr_mode == HDR_BYPASS) ? 0 : 1); |
---|
| 5520 | + VOP_MODULE_SET(vop2, vp, hdr_vivid_path_mode, |
---|
| 5521 | + (hdr_mode == HDR102SDR) ? PQHDR2SDR_WITH_DYNAMIC : hdr_mode); |
---|
| 5522 | + VOP_MODULE_SET(vop2, vp, hdr_vivid_bypass_en, (hdr_mode == HDR_BYPASS) ? 1 : 0); |
---|
| 5523 | + } else { |
---|
| 5524 | + VOP_MODULE_SET(vop2, vp, hdr_vivid_en, 0); |
---|
| 5525 | + } |
---|
| 5526 | + VOP_MODULE_SET(vop2, vp, sdr2hdr_en, vp->sdr2hdr_en); |
---|
| 5527 | + VOP_MODULE_SET(vop2, vp, sdr2hdr_path_en, vp->sdr2hdr_en); |
---|
| 5528 | + VOP_MODULE_SET(vop2, vp, sdr2hdr_auto_gating_en, vp->sdr2hdr_en ? 0 : 1); |
---|
| 5529 | + |
---|
| 5530 | + vop2_writel(vop2, RK3528_SDR_CFG_COE0, hdrvivid_data->sdr2hdr_coe0); |
---|
| 5531 | + vop2_writel(vop2, RK3528_SDR_CFG_COE1, hdrvivid_data->sdr2hdr_coe1); |
---|
| 5532 | + vop2_writel(vop2, RK3528_SDR_CSC_COE00_01, hdrvivid_data->sdr2hdr_csc_coe00_01); |
---|
| 5533 | + vop2_writel(vop2, RK3528_SDR_CSC_COE02_10, hdrvivid_data->sdr2hdr_csc_coe02_10); |
---|
| 5534 | + vop2_writel(vop2, RK3528_SDR_CSC_COE11_12, hdrvivid_data->sdr2hdr_csc_coe11_12); |
---|
| 5535 | + vop2_writel(vop2, RK3528_SDR_CSC_COE20_21, hdrvivid_data->sdr2hdr_csc_coe20_21); |
---|
| 5536 | + vop2_writel(vop2, RK3528_SDR_CSC_COE22, hdrvivid_data->sdr2hdr_csc_coe22); |
---|
| 5537 | + |
---|
| 5538 | + vop2_writel(vop2, RK3528_HDR_PQ_GAMMA, hdrvivid_data->hdr_pq_gamma); |
---|
| 5539 | + vop2_writel(vop2, RK3528_HLG_RFIX_SCALEFAC, hdrvivid_data->hlg_rfix_scalefac); |
---|
| 5540 | + vop2_writel(vop2, RK3528_HLG_MAXLUMA, hdrvivid_data->hlg_maxluma); |
---|
| 5541 | + vop2_writel(vop2, RK3528_HLG_R_TM_LIN2NON, hdrvivid_data->hlg_r_tm_lin2non); |
---|
| 5542 | + |
---|
| 5543 | + vop2_writel(vop2, RK3528_HDR_CSC_COE00_01, hdrvivid_data->hdr_csc_coe00_01); |
---|
| 5544 | + vop2_writel(vop2, RK3528_HDR_CSC_COE02_10, hdrvivid_data->hdr_csc_coe02_10); |
---|
| 5545 | + vop2_writel(vop2, RK3528_HDR_CSC_COE11_12, hdrvivid_data->hdr_csc_coe11_12); |
---|
| 5546 | + vop2_writel(vop2, RK3528_HDR_CSC_COE20_21, hdrvivid_data->hdr_csc_coe20_21); |
---|
| 5547 | + vop2_writel(vop2, RK3528_HDR_CSC_COE22, hdrvivid_data->hdr_csc_coe22); |
---|
| 5548 | + |
---|
| 5549 | + tone_lut_kvaddr = (u32 *)vp->hdr_lut_gem_obj->kvaddr; |
---|
| 5550 | + tone_lut_mst = vp->hdr_lut_gem_obj->dma_addr; |
---|
| 5551 | + |
---|
| 5552 | + for (i = 0; i < RK_HDRVIVID_TONE_SCA_AXI_TAB_LENGTH; i++) |
---|
| 5553 | + *tone_lut_kvaddr++ = hdrvivid_data->tone_sca_axi_tab[i]; |
---|
| 5554 | + |
---|
| 5555 | + VOP_MODULE_SET(vop2, vp, lut_dma_rid, vp->lut_dma_rid - vp->id); |
---|
| 5556 | + VOP_MODULE_SET(vop2, vp, hdr_lut_mode, 1); |
---|
| 5557 | + VOP_MODULE_SET(vop2, vp, hdr_lut_mst, tone_lut_mst); |
---|
| 5558 | + VOP_MODULE_SET(vop2, vp, hdr_lut_update_en, 1); |
---|
| 5559 | + VOP_CTRL_SET(vop2, lut_dma_en, 1); |
---|
| 5560 | + |
---|
| 5561 | + for (i = 0; i < RK_HDRVIVID_GAMMA_CURVE_LENGTH; i++) |
---|
| 5562 | + vop2_writel(vop2, RK3528_HDRGAMMA_CURVE + i * 4, hdrvivid_data->hdrgamma_curve[i]); |
---|
| 5563 | + |
---|
| 5564 | + for (i = 0; i < RK_HDRVIVID_GAMMA_MDFVALUE_LENGTH; i++) |
---|
| 5565 | + vop2_writel(vop2, RK3528_HDRGAMMA_MDFVALUE + i * 4, |
---|
| 5566 | + hdrvivid_data->hdrgamma_mdfvalue[i]); |
---|
| 5567 | + |
---|
| 5568 | + for (i = 0; i < RK_SDR2HDR_INVGAMMA_CURVE_LENGTH; i++) |
---|
| 5569 | + vop2_writel(vop2, RK3528_SDRINVGAMMA_CURVE + i * 4, |
---|
| 5570 | + hdrvivid_data->sdrinvgamma_curve[i]); |
---|
| 5571 | + |
---|
| 5572 | + for (i = 0; i < RK_SDR2HDR_INVGAMMA_S_IDX_LENGTH; i++) |
---|
| 5573 | + vop2_writel(vop2, RK3528_SDRINVGAMMA_STARTIDX + i * 4, |
---|
| 5574 | + hdrvivid_data->sdrinvgamma_startidx[i]); |
---|
| 5575 | + |
---|
| 5576 | + for (i = 0; i < RK_SDR2HDR_INVGAMMA_C_IDX_LENGTH; i++) |
---|
| 5577 | + vop2_writel(vop2, RK3528_SDRINVGAMMA_CHANGEIDX + i * 4, |
---|
| 5578 | + hdrvivid_data->sdrinvgamma_changeidx[i]); |
---|
| 5579 | + |
---|
| 5580 | + for (i = 0; i < RK_SDR2HDR_SMGAIN_LENGTH; i++) |
---|
| 5581 | + vop2_writel(vop2, RK3528_SDR_SMGAIN + i * 4, hdrvivid_data->sdr_smgain[i]); |
---|
| 5582 | +} |
---|
| 5583 | + |
---|
| 5584 | +static void vop3_setup_dynamic_hdr(struct vop2_video_port *vp, uint8_t win_phys_id) |
---|
| 5585 | +{ |
---|
| 5586 | + struct drm_crtc_state *cstate = vp->crtc.state; |
---|
| 5587 | + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(cstate); |
---|
| 5588 | + struct hdr_extend *hdr_data; |
---|
| 5589 | + uint32_t hdr_format; |
---|
| 5590 | + |
---|
| 5591 | + /* If hdr extend data is null, exit hdr mode */ |
---|
| 5592 | + if (!vcstate->hdr_ext_data) { |
---|
| 5593 | + vop3_disable_dynamic_hdr(vp, win_phys_id); |
---|
| 5594 | + return; |
---|
| 5595 | + } |
---|
| 5596 | + |
---|
| 5597 | + hdr_data = (struct hdr_extend *)vcstate->hdr_ext_data->data; |
---|
| 5598 | + hdr_format = hdr_data->hdr_type; |
---|
| 5599 | + |
---|
| 5600 | + switch (hdr_format) { |
---|
| 5601 | + case HDR_NONE: |
---|
| 5602 | + case HDR_HDR10: |
---|
| 5603 | + case HDR_HLGSTATIC: |
---|
| 5604 | + case HDR_HDRVIVID: |
---|
| 5605 | + /* |
---|
| 5606 | + * hdr module support hdr10, hlg, vividhdr |
---|
| 5607 | + * sdr2hdr module support hdrnone for sdr2hdr |
---|
| 5608 | + */ |
---|
| 5609 | + vop3_setup_hdrvivid(vp, win_phys_id); |
---|
| 5610 | + break; |
---|
| 5611 | + default: |
---|
| 5612 | + DRM_DEBUG("unsupprot hdr format:%u\n", hdr_format); |
---|
| 5613 | + break; |
---|
| 5614 | + } |
---|
5157 | 5615 | } |
---|
5158 | 5616 | |
---|
5159 | 5617 | static void vop2_setup_hdr10(struct vop2_video_port *vp, uint8_t win_phys_id) |
---|
.. | .. |
---|
5648 | 6106 | vop2_writel(vop2, dst_alpha_ctrl_offset + offset, alpha.dst_alpha_ctrl.val); |
---|
5649 | 6107 | } |
---|
5650 | 6108 | |
---|
5651 | | - if (vp_data->feature & VOP_FEATURE_HDR10) { |
---|
| 6109 | + if (vp_data->feature & (VOP_FEATURE_HDR10 | VOP_FEATURE_VIVID_HDR)) { |
---|
5652 | 6110 | src_color_ctrl_offset = ovl_regs->hdr_mix_regs->src_color_ctrl.offset; |
---|
5653 | 6111 | dst_color_ctrl_offset = ovl_regs->hdr_mix_regs->dst_color_ctrl.offset; |
---|
5654 | 6112 | src_alpha_ctrl_offset = ovl_regs->hdr_mix_regs->src_alpha_ctrl.offset; |
---|
.. | .. |
---|
5923 | 6381 | struct vop2_cluster cluster; |
---|
5924 | 6382 | uint8_t nr_layers = 0; |
---|
5925 | 6383 | struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); |
---|
| 6384 | + const struct vop2_video_port_data *vp_data = &vop2->data->vp[vp->id]; |
---|
5926 | 6385 | |
---|
5927 | 6386 | vcstate->yuv_overlay = is_yuv_output(vcstate->bus_format); |
---|
5928 | 6387 | vop2_zpos = kmalloc_array(vop2->data->win_size, sizeof(*vop2_zpos), GFP_KERNEL); |
---|
.. | .. |
---|
5982 | 6441 | |
---|
5983 | 6442 | sort(vop2_zpos, nr_layers, sizeof(vop2_zpos[0]), vop2_zpos_cmp, NULL); |
---|
5984 | 6443 | |
---|
5985 | | - if (is_vop3(vop2)) |
---|
| 6444 | + if (is_vop3(vop2)) { |
---|
5986 | 6445 | vop3_setup_layer_sel_for_vp(vp, vop2_zpos); |
---|
5987 | | - else |
---|
5988 | | - vop2_setup_layer_mixer_for_vp(vp, vop2_zpos); |
---|
5989 | | - vop2_setup_hdr10(vp, vop2_zpos[0].win_phys_id); |
---|
5990 | | - if (is_vop3(vop2)) |
---|
| 6446 | + if (vp_data->feature & VOP_FEATURE_VIVID_HDR) |
---|
| 6447 | + vop3_setup_dynamic_hdr(vp, vop2_zpos[0].win_phys_id); |
---|
5991 | 6448 | vop3_setup_alpha(vp, vop2_zpos); |
---|
5992 | | - else |
---|
| 6449 | + vop3_setup_pipe_dly(vp, vop2_zpos); |
---|
| 6450 | + } else { |
---|
| 6451 | + vop2_setup_layer_mixer_for_vp(vp, vop2_zpos); |
---|
| 6452 | + vop2_setup_hdr10(vp, vop2_zpos[0].win_phys_id); |
---|
5993 | 6453 | vop2_setup_alpha(vp, vop2_zpos); |
---|
5994 | | - vop2_setup_dly_for_vp(vp); |
---|
5995 | | - vop2_setup_dly_for_window(vp, vop2_zpos); |
---|
| 6454 | + vop2_setup_dly_for_vp(vp); |
---|
| 6455 | + vop2_setup_dly_for_window(vp, vop2_zpos); |
---|
| 6456 | + } |
---|
5996 | 6457 | } else { |
---|
5997 | | - if (!is_vop3(vop2)) |
---|
| 6458 | + if (!is_vop3(vop2)) { |
---|
5998 | 6459 | vop2_calc_bg_ovl_and_port_mux(vp); |
---|
5999 | | - vop2_setup_dly_for_vp(vp); |
---|
| 6460 | + vop2_setup_dly_for_vp(vp); |
---|
| 6461 | + } else { |
---|
| 6462 | + vop3_setup_pipe_dly(vp, NULL); |
---|
| 6463 | + } |
---|
6000 | 6464 | } |
---|
6001 | 6465 | |
---|
6002 | 6466 | /* The pre alpha overlay of Cluster still need process in one win mode. */ |
---|
.. | .. |
---|
6124 | 6588 | vop2_bcsh_reg_update(vcstate, vp, &bcsh_state); |
---|
6125 | 6589 | } |
---|
6126 | 6590 | |
---|
| 6591 | +static void vop3_post_csc_config(struct drm_crtc *crtc, struct post_acm *acm, struct post_csc *csc) |
---|
| 6592 | +{ |
---|
| 6593 | + struct vop2_video_port *vp = to_vop2_video_port(crtc); |
---|
| 6594 | + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); |
---|
| 6595 | + struct vop2 *vop2 = vp->vop2; |
---|
| 6596 | + struct post_csc_coef csc_coef; |
---|
| 6597 | + bool acm_enable; |
---|
| 6598 | + bool is_input_yuv = false; |
---|
| 6599 | + bool is_output_yuv = false; |
---|
| 6600 | + bool post_r2y_en = false; |
---|
| 6601 | + bool post_csc_en = false; |
---|
| 6602 | + int range_type; |
---|
| 6603 | + |
---|
| 6604 | + if (!acm) |
---|
| 6605 | + acm_enable = false; |
---|
| 6606 | + else |
---|
| 6607 | + acm_enable = acm->acm_enable; |
---|
| 6608 | + |
---|
| 6609 | + if (acm_enable) { |
---|
| 6610 | + if (!vcstate->yuv_overlay) |
---|
| 6611 | + post_r2y_en = true; |
---|
| 6612 | + |
---|
| 6613 | + /* do y2r in csc module */ |
---|
| 6614 | + if (!is_yuv_output(vcstate->bus_format)) |
---|
| 6615 | + post_csc_en = true; |
---|
| 6616 | + } else { |
---|
| 6617 | + if (!vcstate->yuv_overlay && is_yuv_output(vcstate->bus_format)) |
---|
| 6618 | + post_r2y_en = true; |
---|
| 6619 | + |
---|
| 6620 | + /* do y2r in csc module */ |
---|
| 6621 | + if (vcstate->yuv_overlay && !is_yuv_output(vcstate->bus_format)) |
---|
| 6622 | + post_csc_en = true; |
---|
| 6623 | + } |
---|
| 6624 | + |
---|
| 6625 | + if (csc && csc->csc_enable) |
---|
| 6626 | + post_csc_en = true; |
---|
| 6627 | + |
---|
| 6628 | + if (vcstate->yuv_overlay || post_r2y_en) |
---|
| 6629 | + is_input_yuv = true; |
---|
| 6630 | + |
---|
| 6631 | + if (is_yuv_output(vcstate->bus_format)) |
---|
| 6632 | + is_output_yuv = true; |
---|
| 6633 | + |
---|
| 6634 | + vcstate->post_csc_mode = vop2_convert_csc_mode(vcstate->color_space, CSC_13BIT_DEPTH); |
---|
| 6635 | + |
---|
| 6636 | + if (post_csc_en) { |
---|
| 6637 | + rockchip_calc_post_csc(csc, &csc_coef, vcstate->post_csc_mode, is_input_yuv, |
---|
| 6638 | + is_output_yuv); |
---|
| 6639 | + |
---|
| 6640 | + VOP_MODULE_SET(vop2, vp, csc_coe00, csc_coef.csc_coef00); |
---|
| 6641 | + VOP_MODULE_SET(vop2, vp, csc_coe01, csc_coef.csc_coef01); |
---|
| 6642 | + VOP_MODULE_SET(vop2, vp, csc_coe02, csc_coef.csc_coef02); |
---|
| 6643 | + VOP_MODULE_SET(vop2, vp, csc_coe10, csc_coef.csc_coef10); |
---|
| 6644 | + VOP_MODULE_SET(vop2, vp, csc_coe11, csc_coef.csc_coef11); |
---|
| 6645 | + VOP_MODULE_SET(vop2, vp, csc_coe12, csc_coef.csc_coef12); |
---|
| 6646 | + VOP_MODULE_SET(vop2, vp, csc_coe20, csc_coef.csc_coef20); |
---|
| 6647 | + VOP_MODULE_SET(vop2, vp, csc_coe21, csc_coef.csc_coef21); |
---|
| 6648 | + VOP_MODULE_SET(vop2, vp, csc_coe22, csc_coef.csc_coef22); |
---|
| 6649 | + VOP_MODULE_SET(vop2, vp, csc_offset0, csc_coef.csc_dc0); |
---|
| 6650 | + VOP_MODULE_SET(vop2, vp, csc_offset1, csc_coef.csc_dc1); |
---|
| 6651 | + VOP_MODULE_SET(vop2, vp, csc_offset2, csc_coef.csc_dc2); |
---|
| 6652 | + |
---|
| 6653 | + range_type = csc_coef.range_type ? 0 : 1; |
---|
| 6654 | + range_type <<= is_input_yuv ? 0 : 1; |
---|
| 6655 | + VOP_MODULE_SET(vop2, vp, csc_mode, range_type); |
---|
| 6656 | + } |
---|
| 6657 | + |
---|
| 6658 | + VOP_MODULE_SET(vop2, vp, acm_r2y_en, post_r2y_en ? 1 : 0); |
---|
| 6659 | + VOP_MODULE_SET(vop2, vp, csc_en, post_csc_en ? 1 : 0); |
---|
| 6660 | + VOP_MODULE_SET(vop2, vp, acm_r2y_mode, vcstate->post_csc_mode); |
---|
| 6661 | +} |
---|
| 6662 | + |
---|
| 6663 | +static void vop3_post_acm_config(struct drm_crtc *crtc, struct post_acm *acm) |
---|
| 6664 | +{ |
---|
| 6665 | + struct vop2_video_port *vp = to_vop2_video_port(crtc); |
---|
| 6666 | + struct vop2 *vop2 = vp->vop2; |
---|
| 6667 | + struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; |
---|
| 6668 | + s16 *lut_y; |
---|
| 6669 | + s16 *lut_h; |
---|
| 6670 | + s16 *lut_s; |
---|
| 6671 | + u32 value; |
---|
| 6672 | + int i; |
---|
| 6673 | + |
---|
| 6674 | + writel(0, vop2->acm_regs + RK3528_ACM_CTRL); |
---|
| 6675 | + VOP_MODULE_SET(vop2, vp, acm_bypass_en, 0); |
---|
| 6676 | + |
---|
| 6677 | + if (!acm || !acm->acm_enable) |
---|
| 6678 | + return; |
---|
| 6679 | + |
---|
| 6680 | + /* |
---|
| 6681 | + * If acm update parameters, it need disable acm in the first frame, |
---|
| 6682 | + * then update parameters and enable acm in second frame. |
---|
| 6683 | + */ |
---|
| 6684 | + vop2_cfg_done(crtc); |
---|
| 6685 | + readx_poll_timeout(readl, vop2->acm_regs + RK3528_ACM_CTRL, value, !value, 200, 50000); |
---|
| 6686 | + |
---|
| 6687 | + value = RK3528_ACM_ENABLE + ((adjusted_mode->hdisplay & 0xfff) << 8) + |
---|
| 6688 | + ((adjusted_mode->vdisplay & 0xfff) << 20); |
---|
| 6689 | + writel(value, vop2->acm_regs + RK3528_ACM_CTRL); |
---|
| 6690 | + |
---|
| 6691 | + |
---|
| 6692 | + writel(1, vop2->acm_regs + RK3528_ACM_FETCH_START); |
---|
| 6693 | + |
---|
| 6694 | + value = (acm->y_gain & 0x3ff) + ((acm->h_gain << 10) & 0xffc00) + |
---|
| 6695 | + ((acm->s_gain << 20) & 0x3ff00000); |
---|
| 6696 | + writel(value, vop2->acm_regs + RK3528_ACM_DELTA_RANGE); |
---|
| 6697 | + |
---|
| 6698 | + lut_y = &acm->gain_lut_hy[0]; |
---|
| 6699 | + lut_h = &acm->gain_lut_hy[ACM_GAIN_LUT_HY_LENGTH]; |
---|
| 6700 | + lut_s = &acm->gain_lut_hy[ACM_GAIN_LUT_HY_LENGTH * 2]; |
---|
| 6701 | + for (i = 0; i < ACM_GAIN_LUT_HY_LENGTH; i++) { |
---|
| 6702 | + value = (lut_y[i] & 0xff) + ((lut_h[i] << 8) & 0xff00) + |
---|
| 6703 | + ((lut_s[i] << 16) & 0xff0000); |
---|
| 6704 | + writel(value, vop2->acm_regs + RK3528_ACM_YHS_DEL_HY_SEG0 + (i << 2)); |
---|
| 6705 | + } |
---|
| 6706 | + |
---|
| 6707 | + lut_y = &acm->gain_lut_hs[0]; |
---|
| 6708 | + lut_h = &acm->gain_lut_hs[ACM_GAIN_LUT_HS_LENGTH]; |
---|
| 6709 | + lut_s = &acm->gain_lut_hs[ACM_GAIN_LUT_HS_LENGTH * 2]; |
---|
| 6710 | + for (i = 0; i < ACM_GAIN_LUT_HS_LENGTH; i++) { |
---|
| 6711 | + value = (lut_y[i] & 0xff) + ((lut_h[i] << 8) & 0xff00) + |
---|
| 6712 | + ((lut_s[i] << 16) & 0xff0000); |
---|
| 6713 | + writel(value, vop2->acm_regs + RK3528_ACM_YHS_DEL_HS_SEG0 + (i << 2)); |
---|
| 6714 | + } |
---|
| 6715 | + |
---|
| 6716 | + lut_y = &acm->delta_lut_h[0]; |
---|
| 6717 | + lut_h = &acm->delta_lut_h[ACM_DELTA_LUT_H_LENGTH]; |
---|
| 6718 | + lut_s = &acm->delta_lut_h[ACM_DELTA_LUT_H_LENGTH * 2]; |
---|
| 6719 | + for (i = 0; i < ACM_DELTA_LUT_H_LENGTH; i++) { |
---|
| 6720 | + value = (lut_y[i] & 0x3ff) + ((lut_h[i] << 12) & 0xff000) + |
---|
| 6721 | + ((lut_s[i] << 20) & 0x3ff00000); |
---|
| 6722 | + writel(value, vop2->acm_regs + RK3528_ACM_YHS_DEL_HGAIN_SEG0 + (i << 2)); |
---|
| 6723 | + } |
---|
| 6724 | + |
---|
| 6725 | + writel(1, vop2->acm_regs + RK3528_ACM_FETCH_DONE); |
---|
| 6726 | +} |
---|
| 6727 | + |
---|
| 6728 | +static void vop3_post_config(struct drm_crtc *crtc) |
---|
| 6729 | +{ |
---|
| 6730 | + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); |
---|
| 6731 | + struct vop2_video_port *vp = to_vop2_video_port(crtc); |
---|
| 6732 | + struct post_acm *acm; |
---|
| 6733 | + struct post_csc *csc; |
---|
| 6734 | + |
---|
| 6735 | + csc = vcstate->post_csc_data ? (struct post_csc *)vcstate->post_csc_data->data : NULL; |
---|
| 6736 | + if (csc && memcmp(&vp->csc_info, csc, sizeof(struct post_csc))) |
---|
| 6737 | + memcpy(&vp->csc_info, csc, sizeof(struct post_csc)); |
---|
| 6738 | + vop3_post_csc_config(crtc, &vp->acm_info, &vp->csc_info); |
---|
| 6739 | + |
---|
| 6740 | + acm = vcstate->acm_lut_data ? (struct post_acm *)vcstate->acm_lut_data->data : NULL; |
---|
| 6741 | + |
---|
| 6742 | + if (acm && memcmp(&vp->acm_info, acm, sizeof(struct post_acm))) { |
---|
| 6743 | + memcpy(&vp->acm_info, acm, sizeof(struct post_acm)); |
---|
| 6744 | + vop3_post_acm_config(crtc, &vp->acm_info); |
---|
| 6745 | + } else if (crtc->state->active_changed) { |
---|
| 6746 | + vop3_post_acm_config(crtc, &vp->acm_info); |
---|
| 6747 | + } |
---|
| 6748 | +} |
---|
| 6749 | + |
---|
6127 | 6750 | static void vop2_cfg_update(struct drm_crtc *crtc, |
---|
6128 | 6751 | struct drm_crtc_state *old_crtc_state) |
---|
6129 | 6752 | { |
---|
6130 | 6753 | struct vop2_video_port *vp = to_vop2_video_port(crtc); |
---|
6131 | 6754 | struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); |
---|
6132 | 6755 | struct vop2 *vop2 = vp->vop2; |
---|
| 6756 | + const struct vop2_data *vop2_data = vop2->data; |
---|
| 6757 | + const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; |
---|
6133 | 6758 | uint32_t val; |
---|
6134 | 6759 | uint32_t r, g, b; |
---|
| 6760 | + uint8_t out_mode; |
---|
6135 | 6761 | |
---|
6136 | 6762 | spin_lock(&vop2->reg_lock); |
---|
| 6763 | + |
---|
| 6764 | + if ((vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA && |
---|
| 6765 | + !(vp_data->feature & VOP_FEATURE_OUTPUT_10BIT)) || |
---|
| 6766 | + vcstate->output_if & VOP_OUTPUT_IF_BT656) |
---|
| 6767 | + out_mode = ROCKCHIP_OUT_MODE_P888; |
---|
| 6768 | + else |
---|
| 6769 | + out_mode = vcstate->output_mode; |
---|
| 6770 | + VOP_MODULE_SET(vop2, vp, out_mode, out_mode); |
---|
| 6771 | + |
---|
| 6772 | + if (vop2_output_uv_swap(vcstate->bus_format, vcstate->output_mode)) |
---|
| 6773 | + VOP_MODULE_SET(vop2, vp, dsp_data_swap, DSP_RB_SWAP); |
---|
| 6774 | + else |
---|
| 6775 | + VOP_MODULE_SET(vop2, vp, dsp_data_swap, 0); |
---|
| 6776 | + |
---|
| 6777 | + vop2_dither_setup(crtc); |
---|
6137 | 6778 | |
---|
6138 | 6779 | VOP_MODULE_SET(vop2, vp, overlay_mode, vcstate->yuv_overlay); |
---|
6139 | 6780 | |
---|
.. | .. |
---|
6162 | 6803 | vop2_post_config(crtc); |
---|
6163 | 6804 | |
---|
6164 | 6805 | spin_unlock(&vop2->reg_lock); |
---|
| 6806 | + |
---|
| 6807 | + if (vp_data->feature & (VOP_FEATURE_POST_ACM | VOP_FEATURE_POST_CSC)) |
---|
| 6808 | + vop3_post_config(crtc); |
---|
6165 | 6809 | } |
---|
6166 | 6810 | |
---|
6167 | 6811 | static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_cstate) |
---|
.. | .. |
---|
6304 | 6948 | return NULL; |
---|
6305 | 6949 | |
---|
6306 | 6950 | vcstate->vp_id = vp->id; |
---|
| 6951 | + if (vcstate->hdr_ext_data) |
---|
| 6952 | + drm_property_blob_get(vcstate->hdr_ext_data); |
---|
| 6953 | + if (vcstate->acm_lut_data) |
---|
| 6954 | + drm_property_blob_get(vcstate->acm_lut_data); |
---|
| 6955 | + if (vcstate->post_csc_data) |
---|
| 6956 | + drm_property_blob_get(vcstate->post_csc_data); |
---|
| 6957 | + |
---|
6307 | 6958 | __drm_atomic_helper_crtc_duplicate_state(crtc, &vcstate->base); |
---|
6308 | 6959 | return &vcstate->base; |
---|
6309 | 6960 | } |
---|
.. | .. |
---|
6314 | 6965 | struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(state); |
---|
6315 | 6966 | |
---|
6316 | 6967 | __drm_atomic_helper_crtc_destroy_state(&vcstate->base); |
---|
| 6968 | + drm_property_blob_put(vcstate->hdr_ext_data); |
---|
| 6969 | + drm_property_blob_put(vcstate->acm_lut_data); |
---|
| 6970 | + drm_property_blob_put(vcstate->post_csc_data); |
---|
6317 | 6971 | kfree(vcstate); |
---|
6318 | 6972 | } |
---|
6319 | 6973 | |
---|
.. | .. |
---|
6436 | 7090 | return 0; |
---|
6437 | 7091 | } |
---|
6438 | 7092 | |
---|
| 7093 | + if (property == vp->hdr_ext_data_prop) |
---|
| 7094 | + return 0; |
---|
| 7095 | + |
---|
| 7096 | + if (property == vp->acm_lut_data_prop) |
---|
| 7097 | + return 0; |
---|
| 7098 | + |
---|
| 7099 | + if (property == vp->post_csc_data_prop) |
---|
| 7100 | + return 0; |
---|
| 7101 | + |
---|
6439 | 7102 | DRM_ERROR("failed to get vop2 crtc property: %s\n", property->name); |
---|
6440 | 7103 | |
---|
6441 | 7104 | return -EINVAL; |
---|
| 7105 | +} |
---|
| 7106 | + |
---|
| 7107 | +/* copied from drm_atomic.c */ |
---|
| 7108 | +static int |
---|
| 7109 | +vop2_atomic_replace_property_blob_from_id(struct drm_device *dev, |
---|
| 7110 | + struct drm_property_blob **blob, |
---|
| 7111 | + uint64_t blob_id, |
---|
| 7112 | + ssize_t expected_size, |
---|
| 7113 | + ssize_t expected_elem_size, |
---|
| 7114 | + bool *replaced) |
---|
| 7115 | +{ |
---|
| 7116 | + struct drm_property_blob *new_blob = NULL; |
---|
| 7117 | + |
---|
| 7118 | + if (blob_id != 0) { |
---|
| 7119 | + new_blob = drm_property_lookup_blob(dev, blob_id); |
---|
| 7120 | + if (new_blob == NULL) |
---|
| 7121 | + return -EINVAL; |
---|
| 7122 | + |
---|
| 7123 | + if (expected_size > 0 && |
---|
| 7124 | + new_blob->length != expected_size) { |
---|
| 7125 | + drm_property_blob_put(new_blob); |
---|
| 7126 | + return -EINVAL; |
---|
| 7127 | + } |
---|
| 7128 | + if (expected_elem_size > 0 && |
---|
| 7129 | + new_blob->length % expected_elem_size != 0) { |
---|
| 7130 | + drm_property_blob_put(new_blob); |
---|
| 7131 | + return -EINVAL; |
---|
| 7132 | + } |
---|
| 7133 | + } |
---|
| 7134 | + |
---|
| 7135 | + *replaced |= drm_property_replace_blob(blob, new_blob); |
---|
| 7136 | + drm_property_blob_put(new_blob); |
---|
| 7137 | + |
---|
| 7138 | + return 0; |
---|
6442 | 7139 | } |
---|
6443 | 7140 | |
---|
6444 | 7141 | static int vop2_crtc_atomic_set_property(struct drm_crtc *crtc, |
---|
.. | .. |
---|
6451 | 7148 | struct drm_mode_config *mode_config = &drm_dev->mode_config; |
---|
6452 | 7149 | struct vop2_video_port *vp = to_vop2_video_port(crtc); |
---|
6453 | 7150 | struct vop2 *vop2 = vp->vop2; |
---|
| 7151 | + bool replaced = false; |
---|
| 7152 | + int ret; |
---|
6454 | 7153 | |
---|
6455 | 7154 | if (property == mode_config->tv_left_margin_property) { |
---|
6456 | 7155 | vcstate->left_margin = val; |
---|
.. | .. |
---|
6481 | 7180 | if (property == vop2->line_flag_prop) { |
---|
6482 | 7181 | vcstate->line_flag = val; |
---|
6483 | 7182 | return 0; |
---|
| 7183 | + } |
---|
| 7184 | + |
---|
| 7185 | + if (property == vp->hdr_ext_data_prop) { |
---|
| 7186 | + ret = vop2_atomic_replace_property_blob_from_id(drm_dev, |
---|
| 7187 | + &vcstate->hdr_ext_data, |
---|
| 7188 | + val, |
---|
| 7189 | + -1, -1, |
---|
| 7190 | + &replaced); |
---|
| 7191 | + return ret; |
---|
| 7192 | + } |
---|
| 7193 | + |
---|
| 7194 | + if (property == vp->acm_lut_data_prop) { |
---|
| 7195 | + ret = vop2_atomic_replace_property_blob_from_id(drm_dev, |
---|
| 7196 | + &vcstate->acm_lut_data, |
---|
| 7197 | + val, |
---|
| 7198 | + sizeof(struct post_acm), -1, |
---|
| 7199 | + &replaced); |
---|
| 7200 | + return ret; |
---|
| 7201 | + } |
---|
| 7202 | + |
---|
| 7203 | + if (property == vp->post_csc_data_prop) { |
---|
| 7204 | + ret = vop2_atomic_replace_property_blob_from_id(drm_dev, |
---|
| 7205 | + &vcstate->post_csc_data, |
---|
| 7206 | + val, |
---|
| 7207 | + sizeof(struct post_csc), -1, |
---|
| 7208 | + &replaced); |
---|
| 7209 | + return ret; |
---|
6484 | 7210 | } |
---|
6485 | 7211 | |
---|
6486 | 7212 | DRM_ERROR("failed to set vop2 crtc property %s\n", property->name); |
---|
.. | .. |
---|
6694 | 7420 | ret = IRQ_HANDLED; |
---|
6695 | 7421 | } |
---|
6696 | 7422 | |
---|
| 7423 | + if (vop2->version == VOP_VERSION_RK3528 && vp->id == 1) { |
---|
| 7424 | + if (active_irqs & POST_BUF_EMPTY_INTR) |
---|
| 7425 | + atomic_inc(&vp->post_buf_empty_flag); |
---|
| 7426 | + |
---|
| 7427 | + if (active_irqs & FS_FIELD_INTR && |
---|
| 7428 | + (atomic_read(&vp->post_buf_empty_flag) > 0 || |
---|
| 7429 | + vp->need_reset_p2i_flag == true)) |
---|
| 7430 | + queue_work(vop2->workqueue, &vop2->post_buf_empty_work); |
---|
| 7431 | + } |
---|
| 7432 | + |
---|
6697 | 7433 | if (active_irqs & FS_FIELD_INTR) { |
---|
6698 | 7434 | vop2_wb_handler(vp); |
---|
6699 | 7435 | if (likely(!vp->skip_vsync) || (vp->layer_sel_update == false)) { |
---|
.. | .. |
---|
6784 | 7520 | return 0; |
---|
6785 | 7521 | } |
---|
6786 | 7522 | |
---|
| 7523 | +static bool vop3_ignore_plane(struct vop2 *vop2, struct vop2_win *win) |
---|
| 7524 | +{ |
---|
| 7525 | + if (!is_vop3(vop2)) |
---|
| 7526 | + return false; |
---|
| 7527 | + |
---|
| 7528 | + if (vop2->esmart_lb_mode == VOP3_ESMART_8K_MODE && |
---|
| 7529 | + win->phys_id != ROCKCHIP_VOP2_ESMART0) |
---|
| 7530 | + return true; |
---|
| 7531 | + else if (vop2->esmart_lb_mode == VOP3_ESMART_4K_4K_MODE && |
---|
| 7532 | + (win->phys_id == ROCKCHIP_VOP2_ESMART1 || win->phys_id == ROCKCHIP_VOP2_ESMART3)) |
---|
| 7533 | + return true; |
---|
| 7534 | + else if (vop2->esmart_lb_mode == VOP3_ESMART_4K_2K_2K_MODE && |
---|
| 7535 | + win->phys_id == ROCKCHIP_VOP2_ESMART1) |
---|
| 7536 | + return true; |
---|
| 7537 | + else |
---|
| 7538 | + return false; |
---|
| 7539 | +} |
---|
| 7540 | + |
---|
| 7541 | +static u32 vop3_esmart_linebuffer_size(struct vop2 *vop2, struct vop2_win *win) |
---|
| 7542 | +{ |
---|
| 7543 | + if (!is_vop3(vop2) || vop2_cluster_window(win)) |
---|
| 7544 | + return vop2->data->max_output.width; |
---|
| 7545 | + |
---|
| 7546 | + if (vop2->esmart_lb_mode == VOP3_ESMART_2K_2K_2K_2K_MODE || |
---|
| 7547 | + (vop2->esmart_lb_mode == VOP3_ESMART_4K_2K_2K_MODE && win->phys_id != ROCKCHIP_VOP2_ESMART0)) |
---|
| 7548 | + return vop2->data->max_output.width / 2; |
---|
| 7549 | + else |
---|
| 7550 | + return vop2->data->max_output.width; |
---|
| 7551 | +} |
---|
| 7552 | + |
---|
| 7553 | +static void vop3_init_esmart_scale_engine(struct vop2 *vop2) |
---|
| 7554 | +{ |
---|
| 7555 | + u8 scale_engine_num = 0; |
---|
| 7556 | + struct drm_plane *plane = NULL; |
---|
| 7557 | + |
---|
| 7558 | + drm_for_each_plane(plane, vop2->drm_dev) { |
---|
| 7559 | + struct vop2_win *win = to_vop2_win(plane); |
---|
| 7560 | + |
---|
| 7561 | + if (win->parent || vop2_cluster_window(win)) |
---|
| 7562 | + continue; |
---|
| 7563 | + |
---|
| 7564 | + win->scale_engine_num = scale_engine_num++; |
---|
| 7565 | + } |
---|
| 7566 | +} |
---|
| 7567 | + |
---|
6787 | 7568 | static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win, unsigned long possible_crtcs) |
---|
6788 | 7569 | { |
---|
6789 | 7570 | struct rockchip_drm_private *private = vop2->drm_dev->dev_private; |
---|
.. | .. |
---|
6807 | 7588 | if (win->feature & WIN_FEATURE_CLUSTER_SUB) |
---|
6808 | 7589 | return -EACCES; |
---|
6809 | 7590 | } |
---|
| 7591 | + |
---|
| 7592 | + /* ignore some plane register according vop3 esmart lb mode */ |
---|
| 7593 | + if (vop3_ignore_plane(vop2, win)) |
---|
| 7594 | + return -EACCES; |
---|
6810 | 7595 | |
---|
6811 | 7596 | ret = drm_universal_plane_init(vop2->drm_dev, &win->base, possible_crtcs, |
---|
6812 | 7597 | &vop2_plane_funcs, win->formats, win->nformats, |
---|
.. | .. |
---|
6847 | 7632 | "INPUT_WIDTH", 0, max_width); |
---|
6848 | 7633 | win->input_height_prop = drm_property_create_range(vop2->drm_dev, DRM_MODE_PROP_IMMUTABLE, |
---|
6849 | 7634 | "INPUT_HEIGHT", 0, max_height); |
---|
6850 | | - max_width = vop2->data->max_output.width; |
---|
| 7635 | + max_width = vop3_esmart_linebuffer_size(vop2, win); |
---|
6851 | 7636 | max_height = vop2->data->max_output.height; |
---|
6852 | 7637 | if (win->feature & WIN_FEATURE_CLUSTER_SUB) |
---|
6853 | 7638 | max_width >>= 1; |
---|
.. | .. |
---|
6883 | 7668 | return 0; |
---|
6884 | 7669 | } |
---|
6885 | 7670 | |
---|
6886 | | -static struct drm_plane *vop2_cursor_plane_init(struct vop2_video_port *vp, |
---|
6887 | | - unsigned long possible_crtcs) |
---|
| 7671 | +static struct drm_plane *vop2_cursor_plane_init(struct vop2_video_port *vp) |
---|
6888 | 7672 | { |
---|
6889 | 7673 | struct vop2 *vop2 = vp->vop2; |
---|
6890 | 7674 | struct drm_plane *cursor = NULL; |
---|
6891 | 7675 | struct vop2_win *win; |
---|
| 7676 | + unsigned long possible_crtcs = 0; |
---|
6892 | 7677 | |
---|
6893 | 7678 | win = vop2_find_win_by_phys_id(vop2, vp->cursor_win_id); |
---|
6894 | 7679 | if (win) { |
---|
| 7680 | + if (vop2->disable_win_move) { |
---|
| 7681 | + const struct vop2_data *vop2_data = vop2->data; |
---|
| 7682 | + struct drm_crtc *crtc = vop2_find_crtc_by_plane_mask(vop2, win->phys_id); |
---|
| 7683 | + |
---|
| 7684 | + if (crtc) |
---|
| 7685 | + possible_crtcs = drm_crtc_mask(crtc); |
---|
| 7686 | + else |
---|
| 7687 | + possible_crtcs = (1 << vop2_data->nr_vps) - 1; |
---|
| 7688 | + } |
---|
| 7689 | + |
---|
| 7690 | + if (win->possible_crtcs) |
---|
| 7691 | + possible_crtcs = win->possible_crtcs; |
---|
6895 | 7692 | win->type = DRM_PLANE_TYPE_CURSOR; |
---|
6896 | 7693 | win->zpos = vop2->registered_num_wins - 1; |
---|
6897 | 7694 | if (!vop2_plane_init(vop2, win, possible_crtcs)) |
---|
.. | .. |
---|
6925 | 7722 | if (!lut_len) |
---|
6926 | 7723 | continue; |
---|
6927 | 7724 | vp->gamma_lut_len = vp_data->gamma_lut_len; |
---|
| 7725 | + vp->lut_dma_rid = vp_data->lut_dma_rid; |
---|
6928 | 7726 | vp->lut = devm_kmalloc_array(dev, lut_len, sizeof(*vp->lut), |
---|
6929 | 7727 | GFP_KERNEL); |
---|
6930 | 7728 | if (!vp->lut) |
---|
.. | .. |
---|
7009 | 7807 | return 0; |
---|
7010 | 7808 | } |
---|
7011 | 7809 | |
---|
| 7810 | +static int vop2_crtc_create_hdr_property(struct vop2 *vop2, struct drm_crtc *crtc) |
---|
| 7811 | +{ |
---|
| 7812 | + struct vop2_video_port *vp = to_vop2_video_port(crtc); |
---|
| 7813 | + struct drm_property *prop; |
---|
| 7814 | + |
---|
| 7815 | + prop = drm_property_create(vop2->drm_dev, DRM_MODE_PROP_BLOB, "HDR_EXT_DATA", 0); |
---|
| 7816 | + if (!prop) { |
---|
| 7817 | + DRM_DEV_ERROR(vop2->dev, "create hdr ext data prop for vp%d failed\n", vp->id); |
---|
| 7818 | + return -ENOMEM; |
---|
| 7819 | + } |
---|
| 7820 | + vp->hdr_ext_data_prop = prop; |
---|
| 7821 | + drm_object_attach_property(&crtc->base, vp->hdr_ext_data_prop, 0); |
---|
| 7822 | + |
---|
| 7823 | + return 0; |
---|
| 7824 | +} |
---|
| 7825 | + |
---|
| 7826 | +static int vop2_crtc_create_post_acm_property(struct vop2 *vop2, struct drm_crtc *crtc) |
---|
| 7827 | +{ |
---|
| 7828 | + struct vop2_video_port *vp = to_vop2_video_port(crtc); |
---|
| 7829 | + struct drm_property *prop; |
---|
| 7830 | + |
---|
| 7831 | + prop = drm_property_create(vop2->drm_dev, DRM_MODE_PROP_BLOB, "ACM_LUT_DATA", 0); |
---|
| 7832 | + if (!prop) { |
---|
| 7833 | + DRM_DEV_ERROR(vop2->dev, "create acm lut data prop for vp%d failed\n", vp->id); |
---|
| 7834 | + return -ENOMEM; |
---|
| 7835 | + } |
---|
| 7836 | + vp->acm_lut_data_prop = prop; |
---|
| 7837 | + drm_object_attach_property(&crtc->base, vp->acm_lut_data_prop, 0); |
---|
| 7838 | + |
---|
| 7839 | + return 0; |
---|
| 7840 | +} |
---|
| 7841 | + |
---|
| 7842 | +static int vop2_crtc_create_post_csc_property(struct vop2 *vop2, struct drm_crtc *crtc) |
---|
| 7843 | +{ |
---|
| 7844 | + struct vop2_video_port *vp = to_vop2_video_port(crtc); |
---|
| 7845 | + struct drm_property *prop; |
---|
| 7846 | + |
---|
| 7847 | + prop = drm_property_create(vop2->drm_dev, DRM_MODE_PROP_BLOB, "POST_CSC_DATA", 0); |
---|
| 7848 | + if (!prop) { |
---|
| 7849 | + DRM_DEV_ERROR(vop2->dev, "create post csc data prop for vp%d failed\n", vp->id); |
---|
| 7850 | + return -ENOMEM; |
---|
| 7851 | + } |
---|
| 7852 | + vp->post_csc_data_prop = prop; |
---|
| 7853 | + drm_object_attach_property(&crtc->base, vp->post_csc_data_prop, 0); |
---|
| 7854 | + |
---|
| 7855 | + return 0; |
---|
| 7856 | +} |
---|
7012 | 7857 | #define RK3566_MIRROR_PLANE_MASK (BIT(ROCKCHIP_VOP2_CLUSTER1) | BIT(ROCKCHIP_VOP2_ESMART1) | \ |
---|
7013 | 7858 | BIT(ROCKCHIP_VOP2_SMART1)) |
---|
7014 | 7859 | |
---|
.. | .. |
---|
7021 | 7866 | const struct vop2_data *vop2_data = vop2->data; |
---|
7022 | 7867 | struct drm_device *drm_dev = vop2->drm_dev; |
---|
7023 | 7868 | struct device *dev = vop2->dev; |
---|
7024 | | - struct drm_plane *plane; |
---|
| 7869 | + struct drm_plane *primary; |
---|
7025 | 7870 | struct drm_plane *cursor = NULL; |
---|
7026 | 7871 | struct drm_crtc *crtc; |
---|
7027 | 7872 | struct device_node *port; |
---|
.. | .. |
---|
7069 | 7914 | vp->id = vp_data->id; |
---|
7070 | 7915 | vp->regs = vp_data->regs; |
---|
7071 | 7916 | vp->cursor_win_id = -1; |
---|
| 7917 | + primary = NULL; |
---|
| 7918 | + cursor = NULL; |
---|
| 7919 | + |
---|
7072 | 7920 | if (vop2->disable_win_move) |
---|
7073 | 7921 | possible_crtcs = BIT(registered_num_crtcs); |
---|
7074 | 7922 | |
---|
.. | .. |
---|
7116 | 7964 | win->type = DRM_PLANE_TYPE_PRIMARY; |
---|
7117 | 7965 | } |
---|
7118 | 7966 | } else { |
---|
| 7967 | + j = 0; |
---|
7119 | 7968 | while (j < vop2->registered_num_wins) { |
---|
7120 | 7969 | be_used_for_primary_plane = false; |
---|
7121 | 7970 | win = &vop2->win[j]; |
---|
.. | .. |
---|
7157 | 8006 | DRM_DEV_ERROR(vop2->dev, "failed to init primary plane\n"); |
---|
7158 | 8007 | break; |
---|
7159 | 8008 | } |
---|
7160 | | - plane = &win->base; |
---|
| 8009 | + primary = &win->base; |
---|
7161 | 8010 | } |
---|
7162 | 8011 | |
---|
7163 | 8012 | /* some times we want a cursor window for some vp */ |
---|
| 8013 | + if (vp->cursor_win_id < 0) { |
---|
| 8014 | + bool be_used_for_cursor_plane = false; |
---|
| 8015 | + |
---|
| 8016 | + j = 0; |
---|
| 8017 | + while (j < vop2->registered_num_wins) { |
---|
| 8018 | + win = &vop2->win[j++]; |
---|
| 8019 | + |
---|
| 8020 | + if (win->parent || (win->feature & WIN_FEATURE_CLUSTER_SUB)) |
---|
| 8021 | + continue; |
---|
| 8022 | + |
---|
| 8023 | + if (win->type != DRM_PLANE_TYPE_CURSOR) |
---|
| 8024 | + continue; |
---|
| 8025 | + |
---|
| 8026 | + for (k = 0; k < vop2_data->nr_vps; k++) { |
---|
| 8027 | + if (vop2->vps[k].cursor_win_id == win->phys_id) |
---|
| 8028 | + be_used_for_cursor_plane = true; |
---|
| 8029 | + } |
---|
| 8030 | + if (be_used_for_cursor_plane) |
---|
| 8031 | + continue; |
---|
| 8032 | + vp->cursor_win_id = win->phys_id; |
---|
| 8033 | + } |
---|
| 8034 | + } |
---|
| 8035 | + |
---|
7164 | 8036 | if (vp->cursor_win_id >= 0) { |
---|
7165 | | - if (win->possible_crtcs) |
---|
7166 | | - possible_crtcs = win->possible_crtcs; |
---|
7167 | | - cursor = vop2_cursor_plane_init(vp, possible_crtcs); |
---|
| 8037 | + cursor = vop2_cursor_plane_init(vp); |
---|
7168 | 8038 | if (!cursor) |
---|
7169 | 8039 | DRM_WARN("failed to init cursor plane for vp%d\n", vp->id); |
---|
7170 | 8040 | else |
---|
7171 | 8041 | DRM_DEV_INFO(vop2->dev, "%s as cursor plane for vp%d\n", |
---|
7172 | 8042 | cursor->name, vp->id); |
---|
7173 | | - } else { |
---|
7174 | | - cursor = NULL; |
---|
7175 | 8043 | } |
---|
7176 | 8044 | |
---|
7177 | | - ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, cursor, &vop2_crtc_funcs, |
---|
| 8045 | + ret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, &vop2_crtc_funcs, |
---|
7178 | 8046 | "video_port%d", vp->id); |
---|
7179 | 8047 | if (ret) { |
---|
7180 | 8048 | DRM_DEV_ERROR(vop2->dev, "crtc init for video_port%d failed\n", i); |
---|
.. | .. |
---|
7202 | 8070 | drm_dev->mode_config.tv_top_margin_property, 100); |
---|
7203 | 8071 | drm_object_attach_property(&crtc->base, |
---|
7204 | 8072 | drm_dev->mode_config.tv_bottom_margin_property, 100); |
---|
7205 | | - vop2_crtc_create_plane_mask_property(vop2, crtc, plane_mask); |
---|
| 8073 | + if (plane_mask) |
---|
| 8074 | + vop2_crtc_create_plane_mask_property(vop2, crtc, plane_mask); |
---|
| 8075 | + |
---|
| 8076 | + if (vp_data->feature & VOP_FEATURE_VIVID_HDR) { |
---|
| 8077 | + vop2_crtc_create_hdr_property(vop2, crtc); |
---|
| 8078 | + vp->hdr_lut_gem_obj = rockchip_gem_create_object(vop2->drm_dev, |
---|
| 8079 | + RK_HDRVIVID_TONE_SCA_AXI_TAB_LENGTH * 4, true, 0); |
---|
| 8080 | + if (IS_ERR(vp->hdr_lut_gem_obj)) { |
---|
| 8081 | + DRM_ERROR("create hdr lut obj failed\n"); |
---|
| 8082 | + return -ENOMEM; |
---|
| 8083 | + } |
---|
| 8084 | + } |
---|
| 8085 | + if (vp_data->feature & VOP_FEATURE_POST_ACM) |
---|
| 8086 | + vop2_crtc_create_post_acm_property(vop2, crtc); |
---|
| 8087 | + if (vp_data->feature & VOP_FEATURE_POST_CSC) |
---|
| 8088 | + vop2_crtc_create_post_csc_property(vop2, crtc); |
---|
| 8089 | + |
---|
7206 | 8090 | registered_num_crtcs++; |
---|
7207 | 8091 | } |
---|
7208 | 8092 | |
---|
.. | .. |
---|
7260 | 8144 | DRM_WARN("failed to init overlay plane %s, ret:%d\n", win->name, ret); |
---|
7261 | 8145 | } |
---|
7262 | 8146 | |
---|
| 8147 | + if (is_vop3(vop2)) |
---|
| 8148 | + vop3_init_esmart_scale_engine(vop2); |
---|
| 8149 | + |
---|
7263 | 8150 | return registered_num_crtcs; |
---|
7264 | 8151 | } |
---|
7265 | 8152 | |
---|
7266 | 8153 | static void vop2_destroy_crtc(struct drm_crtc *crtc) |
---|
7267 | 8154 | { |
---|
7268 | 8155 | struct vop2_video_port *vp = to_vop2_video_port(crtc); |
---|
| 8156 | + |
---|
| 8157 | + if (vp->hdr_lut_gem_obj) |
---|
| 8158 | + rockchip_gem_free_object(&vp->hdr_lut_gem_obj->base); |
---|
7269 | 8159 | |
---|
7270 | 8160 | of_node_put(crtc->port); |
---|
7271 | 8161 | |
---|
.. | .. |
---|
7322 | 8212 | win->axi_id = win_data->axi_id; |
---|
7323 | 8213 | win->axi_yrgb_id = win_data->axi_yrgb_id; |
---|
7324 | 8214 | win->axi_uv_id = win_data->axi_uv_id; |
---|
7325 | | - win->scale_engine_num = win_data->scale_engine_num; |
---|
7326 | 8215 | win->possible_crtcs = win_data->possible_crtcs; |
---|
7327 | 8216 | |
---|
7328 | 8217 | num_wins++; |
---|
.. | .. |
---|
7351 | 8240 | area->vsd_filter_mode = win_data->vsd_filter_mode; |
---|
7352 | 8241 | area->hsd_pre_filter_mode = win_data->hsd_pre_filter_mode; |
---|
7353 | 8242 | area->vsd_pre_filter_mode = win_data->vsd_pre_filter_mode; |
---|
| 8243 | + area->possible_crtcs = win->possible_crtcs; |
---|
7354 | 8244 | |
---|
7355 | 8245 | area->vop2 = vop2; |
---|
7356 | 8246 | area->win_id = i; |
---|
.. | .. |
---|
7414 | 8304 | return 0; |
---|
7415 | 8305 | } |
---|
7416 | 8306 | |
---|
| 8307 | +static void post_buf_empty_work_event(struct work_struct *work) |
---|
| 8308 | +{ |
---|
| 8309 | + struct vop2 *vop2 = container_of(work, struct vop2, post_buf_empty_work); |
---|
| 8310 | + struct rockchip_drm_private *private = vop2->drm_dev->dev_private; |
---|
| 8311 | + struct vop2_video_port *vp = &vop2->vps[1]; |
---|
| 8312 | + |
---|
| 8313 | + /* |
---|
| 8314 | + * For RK3528, VP1 only supports NTSC and PAL mode(both interlace). If |
---|
| 8315 | + * POST_BUF_EMPTY_INTR comes, it is needed to reset the p2i_en bit, in |
---|
| 8316 | + * order to update the line parity flag, which ensures the correct order |
---|
| 8317 | + * of odd and even lines. |
---|
| 8318 | + */ |
---|
| 8319 | + if (vop2->version == VOP_VERSION_RK3528) { |
---|
| 8320 | + if (atomic_read(&vp->post_buf_empty_flag) > 0) { |
---|
| 8321 | + atomic_set(&vp->post_buf_empty_flag, 0); |
---|
| 8322 | + |
---|
| 8323 | + mutex_lock(&private->ovl_lock); |
---|
| 8324 | + vop2_wait_for_fs_by_done_bit_status(vp); |
---|
| 8325 | + VOP_MODULE_SET(vop2, vp, p2i_en, 0); |
---|
| 8326 | + vop2_cfg_done(&vp->crtc); |
---|
| 8327 | + vop2_wait_for_fs_by_done_bit_status(vp); |
---|
| 8328 | + mutex_unlock(&private->ovl_lock); |
---|
| 8329 | + |
---|
| 8330 | + vp->need_reset_p2i_flag = true; |
---|
| 8331 | + } else if (vp->need_reset_p2i_flag == true) { |
---|
| 8332 | + mutex_lock(&private->ovl_lock); |
---|
| 8333 | + vop2_wait_for_fs_by_done_bit_status(vp); |
---|
| 8334 | + VOP_MODULE_SET(vop2, vp, p2i_en, 1); |
---|
| 8335 | + vop2_cfg_done(&vp->crtc); |
---|
| 8336 | + vop2_wait_for_fs_by_done_bit_status(vp); |
---|
| 8337 | + mutex_unlock(&private->ovl_lock); |
---|
| 8338 | + |
---|
| 8339 | + vp->need_reset_p2i_flag = false; |
---|
| 8340 | + } |
---|
| 8341 | + } |
---|
| 8342 | +} |
---|
| 8343 | + |
---|
7417 | 8344 | static int vop2_bind(struct device *dev, struct device *master, void *data) |
---|
7418 | 8345 | { |
---|
7419 | 8346 | struct platform_device *pdev = to_platform_device(dev); |
---|
.. | .. |
---|
7454 | 8381 | vop2->disable_afbc_win = of_property_read_bool(dev->of_node, "disable-afbc-win"); |
---|
7455 | 8382 | vop2->disable_win_move = of_property_read_bool(dev->of_node, "disable-win-move"); |
---|
7456 | 8383 | vop2->skip_ref_fb = of_property_read_bool(dev->of_node, "skip-ref-fb"); |
---|
| 8384 | + |
---|
| 8385 | + /* |
---|
| 8386 | + * esmart lb mode default config at vop2_reg.c vop2_data.esmart_lb_mode, |
---|
| 8387 | + * you can rewrite at dts vop node: |
---|
| 8388 | + * |
---|
| 8389 | + * VOP3_ESMART_8K_MODE = 0, |
---|
| 8390 | + * VOP3_ESMART_4K_4K_MODE = 1, |
---|
| 8391 | + * VOP3_ESMART_4K_2K_2K_MODE = 2, |
---|
| 8392 | + * VOP3_ESMART_2K_2K_2K_2K_MODE = 3, |
---|
| 8393 | + * |
---|
| 8394 | + * &vop { |
---|
| 8395 | + * esmart_lb_mode = /bits/ 8 <2>; |
---|
| 8396 | + * }; |
---|
| 8397 | + */ |
---|
| 8398 | + ret = of_property_read_u8(dev->of_node, "esmart_lb_mode", &vop2->esmart_lb_mode); |
---|
| 8399 | + if (ret < 0) |
---|
| 8400 | + vop2->esmart_lb_mode = vop2->data->esmart_lb_mode; |
---|
7457 | 8401 | |
---|
7458 | 8402 | ret = vop2_win_init(vop2); |
---|
7459 | 8403 | if (ret) |
---|
.. | .. |
---|
7538 | 8482 | spin_lock_init(&vop2->irq_lock); |
---|
7539 | 8483 | mutex_init(&vop2->vop2_lock); |
---|
7540 | 8484 | |
---|
| 8485 | + if (vop2->version == VOP_VERSION_RK3528) { |
---|
| 8486 | + atomic_set(&vop2->vps[1].post_buf_empty_flag, 0); |
---|
| 8487 | + vop2->workqueue = create_workqueue("post_buf_empty_wq"); |
---|
| 8488 | + INIT_WORK(&vop2->post_buf_empty_work, post_buf_empty_work_event); |
---|
| 8489 | + } |
---|
| 8490 | + |
---|
7541 | 8491 | ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2); |
---|
7542 | 8492 | if (ret) |
---|
7543 | 8493 | return ret; |
---|