| .. | .. |
|---|
| 20 | 20 | #ifdef CONFIG_DRM_ANALOGIX_DP |
|---|
| 21 | 21 | #include <drm/bridge/analogix_dp.h> |
|---|
| 22 | 22 | #endif |
|---|
| 23 | | -#include <dt-bindings/soc/rockchip-system-status.h> |
|---|
| 24 | 23 | |
|---|
| 25 | 24 | #include <linux/debugfs.h> |
|---|
| 26 | 25 | #include <linux/fixp-arith.h> |
|---|
| .. | .. |
|---|
| 46 | 45 | #include <linux/rockchip/cpu.h> |
|---|
| 47 | 46 | #include <linux/workqueue.h> |
|---|
| 48 | 47 | #include <linux/types.h> |
|---|
| 48 | +#include <soc/rockchip/rockchip_csu.h> |
|---|
| 49 | 49 | #include <soc/rockchip/rockchip_dmc.h> |
|---|
| 50 | 50 | #include <soc/rockchip/rockchip-system-status.h> |
|---|
| 51 | 51 | #include <uapi/linux/videodev2.h> |
|---|
| .. | .. |
|---|
| 643 | 643 | */ |
|---|
| 644 | 644 | uint32_t win_mask; |
|---|
| 645 | 645 | /** |
|---|
| 646 | + * @enabled_win_mask: Bitmask of enabled wins attached to the video port; |
|---|
| 647 | + */ |
|---|
| 648 | + uint32_t enabled_win_mask; |
|---|
| 649 | + |
|---|
| 650 | + /** |
|---|
| 646 | 651 | * @nr_layers: active layers attached to the video port; |
|---|
| 647 | 652 | */ |
|---|
| 648 | 653 | uint8_t nr_layers; |
|---|
| .. | .. |
|---|
| 770 | 775 | */ |
|---|
| 771 | 776 | enum vop2_layer_phy_id primary_plane_phy_id; |
|---|
| 772 | 777 | |
|---|
| 778 | + struct post_acm acm_info; |
|---|
| 779 | + struct post_csc csc_info; |
|---|
| 780 | + |
|---|
| 773 | 781 | /** |
|---|
| 774 | 782 | * @refresh_rate_change: indicate whether refresh rate change |
|---|
| 775 | 783 | */ |
|---|
| .. | .. |
|---|
| 877 | 885 | struct clk *pclk; |
|---|
| 878 | 886 | struct reset_control *ahb_rst; |
|---|
| 879 | 887 | struct reset_control *axi_rst; |
|---|
| 888 | + struct csu_clk *csu_aclk; |
|---|
| 880 | 889 | |
|---|
| 881 | 890 | /* list_head of extend clk */ |
|---|
| 882 | 891 | struct list_head extend_clk_list_head; |
|---|
| .. | .. |
|---|
| 921 | 930 | { MEDIA_BUS_FMT_UYYVYY8_0_5X24, "UYYVYY8_0_5X24" }, |
|---|
| 922 | 931 | { MEDIA_BUS_FMT_YUV10_1X30, "YUV10_1X30" }, |
|---|
| 923 | 932 | { MEDIA_BUS_FMT_UYYVYY10_0_5X30, "UYYVYY10_0_5X30" }, |
|---|
| 933 | + { MEDIA_BUS_FMT_RGB565_2X8_LE, "RGB565_2X8_LE" }, |
|---|
| 924 | 934 | { MEDIA_BUS_FMT_RGB888_3X8, "RGB888_3X8" }, |
|---|
| 925 | 935 | { MEDIA_BUS_FMT_RGB888_DUMMY_4X8, "RGB888_DUMMY_4X8" }, |
|---|
| 926 | 936 | { MEDIA_BUS_FMT_RGB888_1X24, "RGB888_1X24" }, |
|---|
| .. | .. |
|---|
| 1870 | 1880 | static inline uint32_t vop2_read_lut(struct vop2 *vop2, uint32_t offset) |
|---|
| 1871 | 1881 | { |
|---|
| 1872 | 1882 | return readl(vop2->lut_regs + offset); |
|---|
| 1883 | +} |
|---|
| 1884 | + |
|---|
| 1885 | +static bool is_linear_10bit_yuv(uint32_t format) |
|---|
| 1886 | +{ |
|---|
| 1887 | + switch (format) { |
|---|
| 1888 | + case DRM_FORMAT_NV15: |
|---|
| 1889 | + case DRM_FORMAT_NV20: |
|---|
| 1890 | + case DRM_FORMAT_NV30: |
|---|
| 1891 | + return true; |
|---|
| 1892 | + default: |
|---|
| 1893 | + return false; |
|---|
| 1894 | + } |
|---|
| 1873 | 1895 | } |
|---|
| 1874 | 1896 | |
|---|
| 1875 | 1897 | static enum vop2_data_format vop2_convert_format(uint32_t format) |
|---|
| .. | .. |
|---|
| 3223 | 3245 | return 0; |
|---|
| 3224 | 3246 | } |
|---|
| 3225 | 3247 | |
|---|
| 3248 | +static void vop2_wb_encoder_atomic_disable(struct drm_encoder *encoder, |
|---|
| 3249 | + struct drm_atomic_state *state) |
|---|
| 3250 | +{ |
|---|
| 3251 | + struct drm_crtc *crtc = encoder->crtc; |
|---|
| 3252 | + struct vop2_video_port *vp = to_vop2_video_port(crtc); |
|---|
| 3253 | + |
|---|
| 3254 | + if (!crtc->state->active_changed && !crtc->state->mode_changed) { |
|---|
| 3255 | + crtc->state->connectors_changed = false; |
|---|
| 3256 | + DRM_DEBUG("VP%d force change connectors_changed to false when disable wb\n", vp->id); |
|---|
| 3257 | + } |
|---|
| 3258 | +} |
|---|
| 3259 | + |
|---|
| 3226 | 3260 | static const struct drm_encoder_helper_funcs vop2_wb_encoder_helper_funcs = { |
|---|
| 3227 | 3261 | .atomic_check = vop2_wb_encoder_atomic_check, |
|---|
| 3262 | + .atomic_disable = vop2_wb_encoder_atomic_disable, |
|---|
| 3228 | 3263 | }; |
|---|
| 3229 | 3264 | |
|---|
| 3230 | 3265 | static const struct drm_connector_helper_funcs vop2_wb_connector_helper_funcs = { |
|---|
| .. | .. |
|---|
| 3383 | 3418 | |
|---|
| 3384 | 3419 | VOP_MODULE_SET(vop2, vp, dsp_lut_en, 1); |
|---|
| 3385 | 3420 | vop2_write_reg_uncached(vop2, &vp->regs->gamma_update_en, 1); |
|---|
| 3386 | | - vop2_cfg_done(crtc); |
|---|
| 3387 | 3421 | vp->gamma_lut_active = true; |
|---|
| 3388 | 3422 | |
|---|
| 3389 | 3423 | spin_unlock(&vop2->reg_lock); |
|---|
| .. | .. |
|---|
| 3430 | 3464 | rk3588_crtc_load_lut(&vp->rockchip_crtc.crtc, vp->lut); |
|---|
| 3431 | 3465 | if (vcstate->splice_mode) |
|---|
| 3432 | 3466 | rk3588_crtc_load_lut(&splice_vp->rockchip_crtc.crtc, vp->lut); |
|---|
| 3433 | | - vop2_cfg_done(crtc); |
|---|
| 3434 | 3467 | } |
|---|
| 3435 | | - /* |
|---|
| 3436 | | - * maybe appear the following case: |
|---|
| 3437 | | - * -> set gamma |
|---|
| 3438 | | - * -> config done |
|---|
| 3439 | | - * -> atomic commit |
|---|
| 3440 | | - * --> update win format |
|---|
| 3441 | | - * --> update win address |
|---|
| 3442 | | - * ---> here maybe meet vop hardware frame start, and triggle some config take affect. |
|---|
| 3443 | | - * ---> as only some config take affect, this maybe lead to iommu pagefault. |
|---|
| 3444 | | - * --> update win size |
|---|
| 3445 | | - * --> update win other parameters |
|---|
| 3446 | | - * -> config done |
|---|
| 3447 | | - * |
|---|
| 3448 | | - * so we add vop2_wait_for_fs_by_done_bit_status() to make sure the first config done take |
|---|
| 3449 | | - * effect and then to do next frame config. |
|---|
| 3450 | | - */ |
|---|
| 3451 | | - if (VOP_MODULE_GET(vop2, vp, standby) == 0) |
|---|
| 3452 | | - vop2_wait_for_fs_by_done_bit_status(vp); |
|---|
| 3453 | 3468 | } |
|---|
| 3454 | 3469 | |
|---|
| 3455 | 3470 | static void rockchip_vop2_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, |
|---|
| .. | .. |
|---|
| 3491 | 3506 | struct drm_modeset_acquire_ctx *ctx) |
|---|
| 3492 | 3507 | { |
|---|
| 3493 | 3508 | struct vop2_video_port *vp = to_vop2_video_port(crtc); |
|---|
| 3509 | + struct vop2 *vop2 = vp->vop2; |
|---|
| 3494 | 3510 | int i; |
|---|
| 3495 | 3511 | |
|---|
| 3496 | 3512 | if (!vp->lut) |
|---|
| .. | .. |
|---|
| 3505 | 3521 | rockchip_vop2_crtc_fb_gamma_set(crtc, red[i], green[i], |
|---|
| 3506 | 3522 | blue[i], i); |
|---|
| 3507 | 3523 | vop2_crtc_load_lut(crtc); |
|---|
| 3524 | + vop2_cfg_done(crtc); |
|---|
| 3525 | + /* |
|---|
| 3526 | + * maybe appear the following case: |
|---|
| 3527 | + * -> set gamma |
|---|
| 3528 | + * -> config done |
|---|
| 3529 | + * -> atomic commit |
|---|
| 3530 | + * --> update win format |
|---|
| 3531 | + * --> update win address |
|---|
| 3532 | + * ---> here maybe meet vop hardware frame start, and triggle some config take affect. |
|---|
| 3533 | + * ---> as only some config take affect, this maybe lead to iommu pagefault. |
|---|
| 3534 | + * --> update win size |
|---|
| 3535 | + * --> update win other parameters |
|---|
| 3536 | + * -> config done |
|---|
| 3537 | + * |
|---|
| 3538 | + * so we add vop2_wait_for_fs_by_done_bit_status() to make sure the first config done take |
|---|
| 3539 | + * effect and then to do next frame config. |
|---|
| 3540 | + */ |
|---|
| 3541 | + if (VOP_MODULE_GET(vop2, vp, standby) == 0) |
|---|
| 3542 | + vop2_wait_for_fs_by_done_bit_status(vp); |
|---|
| 3508 | 3543 | |
|---|
| 3509 | 3544 | return 0; |
|---|
| 3510 | 3545 | } |
|---|
| .. | .. |
|---|
| 3524 | 3559 | return 0; |
|---|
| 3525 | 3560 | } |
|---|
| 3526 | 3561 | |
|---|
| 3527 | | -#if defined(CONFIG_ROCKCHIP_DRM_CUBIC_LUT) |
|---|
| 3528 | 3562 | static int vop2_crtc_atomic_cubic_lut_set(struct drm_crtc *crtc, |
|---|
| 3529 | 3563 | struct drm_crtc_state *old_state) |
|---|
| 3530 | 3564 | { |
|---|
| .. | .. |
|---|
| 3597 | 3631 | return 0; |
|---|
| 3598 | 3632 | } |
|---|
| 3599 | 3633 | |
|---|
| 3600 | | -static void drm_crtc_enable_cubic_lut(struct drm_crtc *crtc, unsigned int cubic_lut_size) |
|---|
| 3634 | +static void vop2_attach_cubic_lut_prop(struct drm_crtc *crtc, unsigned int cubic_lut_size) |
|---|
| 3601 | 3635 | { |
|---|
| 3602 | | - struct drm_device *dev = crtc->dev; |
|---|
| 3603 | | - struct drm_mode_config *config = &dev->mode_config; |
|---|
| 3636 | + struct rockchip_drm_private *private = crtc->dev->dev_private; |
|---|
| 3604 | 3637 | |
|---|
| 3605 | | - if (cubic_lut_size) { |
|---|
| 3606 | | - drm_object_attach_property(&crtc->base, |
|---|
| 3607 | | - config->cubic_lut_property, 0); |
|---|
| 3608 | | - drm_object_attach_property(&crtc->base, |
|---|
| 3609 | | - config->cubic_lut_size_property, |
|---|
| 3610 | | - cubic_lut_size); |
|---|
| 3611 | | - } |
|---|
| 3638 | + drm_object_attach_property(&crtc->base, private->cubic_lut_prop, 0); |
|---|
| 3639 | + drm_object_attach_property(&crtc->base, private->cubic_lut_size_prop, cubic_lut_size); |
|---|
| 3612 | 3640 | } |
|---|
| 3613 | 3641 | |
|---|
| 3614 | 3642 | static void vop2_cubic_lut_init(struct vop2 *vop2) |
|---|
| .. | .. |
|---|
| 3628 | 3656 | vp->cubic_lut_len = vp_data->cubic_lut_len; |
|---|
| 3629 | 3657 | |
|---|
| 3630 | 3658 | if (vp->cubic_lut_len) |
|---|
| 3631 | | - drm_crtc_enable_cubic_lut(crtc, vp->cubic_lut_len); |
|---|
| 3659 | + vop2_attach_cubic_lut_prop(crtc, vp->cubic_lut_len); |
|---|
| 3632 | 3660 | } |
|---|
| 3633 | 3661 | } |
|---|
| 3634 | | -#else |
|---|
| 3635 | | -static void vop2_cubic_lut_init(struct vop2 *vop2) { } |
|---|
| 3636 | | -#endif |
|---|
| 3637 | 3662 | |
|---|
| 3638 | 3663 | static int vop2_core_clks_prepare_enable(struct vop2 *vop2) |
|---|
| 3639 | 3664 | { |
|---|
| .. | .. |
|---|
| 4276 | 4301 | return 0; |
|---|
| 4277 | 4302 | } |
|---|
| 4278 | 4303 | |
|---|
| 4279 | | -static void vop2_crtc_atomic_disable_for_psr(struct drm_crtc *crtc, |
|---|
| 4280 | | - struct drm_crtc_state *old_state) |
|---|
| 4304 | +static void vop2_crtc_atomic_enter_psr(struct drm_crtc *crtc, struct drm_crtc_state *old_state) |
|---|
| 4281 | 4305 | { |
|---|
| 4282 | 4306 | struct vop2_video_port *vp = to_vop2_video_port(crtc); |
|---|
| 4283 | 4307 | struct vop2 *vop2 = vp->vop2; |
|---|
| 4308 | + struct vop2_win *win; |
|---|
| 4309 | + unsigned long win_mask = vp->enabled_win_mask; |
|---|
| 4310 | + int phys_id; |
|---|
| 4284 | 4311 | |
|---|
| 4285 | | - vop2_disable_all_planes_for_crtc(crtc); |
|---|
| 4312 | + for_each_set_bit(phys_id, &win_mask, ROCKCHIP_MAX_LAYER) { |
|---|
| 4313 | + win = vop2_find_win_by_phys_id(vop2, phys_id); |
|---|
| 4314 | + VOP_WIN_SET(vop2, win, enable, 0); |
|---|
| 4315 | + |
|---|
| 4316 | + if (win->feature & WIN_FEATURE_CLUSTER_MAIN) |
|---|
| 4317 | + VOP_CLUSTER_SET(vop2, win, enable, 0); |
|---|
| 4318 | + } |
|---|
| 4319 | + |
|---|
| 4320 | + vop2_cfg_done(crtc); |
|---|
| 4321 | + vop2_wait_for_fs_by_done_bit_status(vp); |
|---|
| 4286 | 4322 | drm_crtc_vblank_off(crtc); |
|---|
| 4287 | 4323 | if (hweight8(vop2->active_vp_mask) == 1) { |
|---|
| 4288 | 4324 | u32 adjust_aclk_rate = 0; |
|---|
| .. | .. |
|---|
| 4305 | 4341 | } |
|---|
| 4306 | 4342 | } |
|---|
| 4307 | 4343 | |
|---|
| 4344 | +static void vop2_crtc_atomic_exit_psr(struct drm_crtc *crtc, struct drm_crtc_state *old_state) |
|---|
| 4345 | +{ |
|---|
| 4346 | + struct vop2_video_port *vp = to_vop2_video_port(crtc); |
|---|
| 4347 | + struct vop2 *vop2 = vp->vop2; |
|---|
| 4348 | + u32 phys_id; |
|---|
| 4349 | + struct vop2_win *win; |
|---|
| 4350 | + unsigned long enabled_win_mask = vp->enabled_win_mask; |
|---|
| 4351 | + |
|---|
| 4352 | + drm_crtc_vblank_on(crtc); |
|---|
| 4353 | + if (vop2->aclk_rate_reset) |
|---|
| 4354 | + clk_set_rate(vop2->aclk, vop2->aclk_rate); |
|---|
| 4355 | + vop2->aclk_rate_reset = false; |
|---|
| 4356 | + |
|---|
| 4357 | + for_each_set_bit(phys_id, &enabled_win_mask, ROCKCHIP_MAX_LAYER) { |
|---|
| 4358 | + win = vop2_find_win_by_phys_id(vop2, phys_id); |
|---|
| 4359 | + VOP_WIN_SET(vop2, win, enable, 1); |
|---|
| 4360 | + if (win->feature & WIN_FEATURE_CLUSTER_MAIN) |
|---|
| 4361 | + VOP_CLUSTER_SET(vop2, win, enable, 1); |
|---|
| 4362 | + } |
|---|
| 4363 | + |
|---|
| 4364 | + vop2_cfg_done(crtc); |
|---|
| 4365 | + vop2_wait_for_fs_by_done_bit_status(vp); |
|---|
| 4366 | +} |
|---|
| 4367 | + |
|---|
| 4308 | 4368 | static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, |
|---|
| 4309 | 4369 | struct drm_crtc_state *old_state) |
|---|
| 4310 | 4370 | { |
|---|
| .. | .. |
|---|
| 4319 | 4379 | WARN_ON(vp->event); |
|---|
| 4320 | 4380 | |
|---|
| 4321 | 4381 | if (crtc->state->self_refresh_active) { |
|---|
| 4322 | | - vop2_crtc_atomic_disable_for_psr(crtc, old_state); |
|---|
| 4382 | + vop2_crtc_atomic_enter_psr(crtc, old_state); |
|---|
| 4323 | 4383 | goto out; |
|---|
| 4324 | 4384 | } |
|---|
| 4325 | 4385 | |
|---|
| .. | .. |
|---|
| 4370 | 4430 | if (vp->output_if & VOP_OUTPUT_IF_eDP0) |
|---|
| 4371 | 4431 | VOP_GRF_SET(vop2, grf, grf_edp0_en, 0); |
|---|
| 4372 | 4432 | |
|---|
| 4373 | | - if (vp->output_if & VOP_OUTPUT_IF_eDP1) |
|---|
| 4433 | + if (vp->output_if & VOP_OUTPUT_IF_eDP1) { |
|---|
| 4374 | 4434 | VOP_GRF_SET(vop2, grf, grf_edp1_en, 0); |
|---|
| 4435 | + if (dual_channel) |
|---|
| 4436 | + VOP_CTRL_SET(vop2, edp_dual_en, 0); |
|---|
| 4437 | + } |
|---|
| 4375 | 4438 | |
|---|
| 4376 | 4439 | if (vp->output_if & VOP_OUTPUT_IF_HDMI0) { |
|---|
| 4377 | 4440 | VOP_GRF_SET(vop2, grf, grf_hdmi0_dsc_en, 0); |
|---|
| .. | .. |
|---|
| 4381 | 4444 | if (vp->output_if & VOP_OUTPUT_IF_HDMI1) { |
|---|
| 4382 | 4445 | VOP_GRF_SET(vop2, grf, grf_hdmi1_dsc_en, 0); |
|---|
| 4383 | 4446 | VOP_GRF_SET(vop2, grf, grf_hdmi1_en, 0); |
|---|
| 4447 | + if (dual_channel) |
|---|
| 4448 | + VOP_CTRL_SET(vop2, hdmi_dual_en, 0); |
|---|
| 4384 | 4449 | } |
|---|
| 4450 | + |
|---|
| 4451 | + if ((vcstate->output_if & VOP_OUTPUT_IF_DP1) && dual_channel) |
|---|
| 4452 | + VOP_CTRL_SET(vop2, dp_dual_en, 0); |
|---|
| 4453 | + |
|---|
| 4454 | + if ((vcstate->output_if & VOP_OUTPUT_IF_MIPI1) && dual_channel) |
|---|
| 4455 | + VOP_CTRL_SET(vop2, mipi_dual_en, 0); |
|---|
| 4385 | 4456 | |
|---|
| 4386 | 4457 | VOP_MODULE_SET(vop2, vp, dual_channel_en, 0); |
|---|
| 4387 | 4458 | VOP_MODULE_SET(vop2, vp, dual_channel_swap, 0); |
|---|
| .. | .. |
|---|
| 4548 | 4619 | return ret; |
|---|
| 4549 | 4620 | } |
|---|
| 4550 | 4621 | |
|---|
| 4622 | +/* |
|---|
| 4623 | + * 1. NV12/NV16/YUYV xoffset must aligned as 2 pixel; |
|---|
| 4624 | + * 2. NV12/NV15 yoffset must aligned as 2 pixel; |
|---|
| 4625 | + * 3. NV30 xoffset must aligned as 4 pixel; |
|---|
| 4626 | + * 4. NV15/NV20 xoffset must aligend as 8 pixel at rk3568/rk3588/rk3528/rk3562, |
|---|
| 4627 | + * others must aligned as 4 pixel; |
|---|
| 4628 | + */ |
|---|
| 4629 | +static int vop2_linear_yuv_format_check(struct drm_plane *plane, struct drm_plane_state *state) |
|---|
| 4630 | +{ |
|---|
| 4631 | + struct vop2_plane_state *vpstate = to_vop2_plane_state(state); |
|---|
| 4632 | + struct drm_crtc *crtc = state->crtc; |
|---|
| 4633 | + struct vop2_video_port *vp = to_vop2_video_port(crtc); |
|---|
| 4634 | + struct vop2_win *win = to_vop2_win(plane); |
|---|
| 4635 | + struct drm_framebuffer *fb = state->fb; |
|---|
| 4636 | + struct drm_rect *src = &vpstate->src; |
|---|
| 4637 | + u32 val = 0; |
|---|
| 4638 | + |
|---|
| 4639 | + if (vpstate->afbc_en || vpstate->tiled_en || !fb->format->is_yuv) |
|---|
| 4640 | + return 0; |
|---|
| 4641 | + |
|---|
| 4642 | + switch (fb->format->format) { |
|---|
| 4643 | + case DRM_FORMAT_NV12: |
|---|
| 4644 | + case DRM_FORMAT_NV21: |
|---|
| 4645 | + val = src->x1 >> 16; |
|---|
| 4646 | + if (val % 2) { |
|---|
| 4647 | + src->x1 = ALIGN(val, 2) << 16; |
|---|
| 4648 | + DRM_WARN("VP%d %s src x offset[%d] must aligned as 2 pixel at NV12 fmt, and adjust to: %d\n", vp->id, win->name, val, src->x1 >> 16); |
|---|
| 4649 | + } |
|---|
| 4650 | + val = src->y1 >> 16; |
|---|
| 4651 | + if (val % 2) { |
|---|
| 4652 | + src->y1 = ALIGN(val, 2) << 16; |
|---|
| 4653 | + DRM_WARN("VP%d %s src y offset[%d] must aligned as 2 pixel at NV12 fmt, and adjust to: %d\n", vp->id, win->name, val, src->y1 >> 16); |
|---|
| 4654 | + } |
|---|
| 4655 | + break; |
|---|
| 4656 | + case DRM_FORMAT_NV15: |
|---|
| 4657 | + val = src->y1 >> 16; |
|---|
| 4658 | + if (val % 2) { |
|---|
| 4659 | + src->y1 = ALIGN(val, 2) << 16; |
|---|
| 4660 | + DRM_WARN("VP%d %s src y offset[%d] must aligned as 2 pixel at NV15 fmt, and adjust to: %d\n", vp->id, win->name, val, src->y1 >> 16); |
|---|
| 4661 | + } |
|---|
| 4662 | + if (vp->vop2->version == VOP_VERSION_RK3568 || |
|---|
| 4663 | + vp->vop2->version == VOP_VERSION_RK3588 || |
|---|
| 4664 | + vp->vop2->version == VOP_VERSION_RK3528 || |
|---|
| 4665 | + vp->vop2->version == VOP_VERSION_RK3562) { |
|---|
| 4666 | + val = src->x1 >> 16; |
|---|
| 4667 | + if (val % 8) { |
|---|
| 4668 | + src->x1 = ALIGN(val, 8) << 16; |
|---|
| 4669 | + DRM_WARN("VP%d %s src x offset[%d] must aligned as 8 pixel at NV15 fmt, and adjust to: %d\n", vp->id, win->name, val, src->x1 >> 16); |
|---|
| 4670 | + } |
|---|
| 4671 | + } else { |
|---|
| 4672 | + val = src->x1 >> 16; |
|---|
| 4673 | + if (val % 4) { |
|---|
| 4674 | + src->x1 = ALIGN(val, 4) << 16; |
|---|
| 4675 | + DRM_WARN("VP%d %s src x offset[%d] must aligned as 4 pixel at NV15 fmt, and adjust to: %d\n", vp->id, win->name, val, src->x1 >> 16); |
|---|
| 4676 | + } |
|---|
| 4677 | + } |
|---|
| 4678 | + break; |
|---|
| 4679 | + case DRM_FORMAT_NV16: |
|---|
| 4680 | + case DRM_FORMAT_NV61: |
|---|
| 4681 | + case DRM_FORMAT_YUYV: |
|---|
| 4682 | + case DRM_FORMAT_YVYU: |
|---|
| 4683 | + case DRM_FORMAT_VYUY: |
|---|
| 4684 | + case DRM_FORMAT_UYVY: |
|---|
| 4685 | + val = src->x1 >> 16; |
|---|
| 4686 | + if (val % 2) { |
|---|
| 4687 | + src->x1 = ALIGN(val, 2) << 16; |
|---|
| 4688 | + DRM_WARN("VP%d %s src x offset[%d] must aligned as 2 pixel at YUYV fmt, and adjust to: %d\n", vp->id, win->name, val, src->x1 >> 16); |
|---|
| 4689 | + } |
|---|
| 4690 | + break; |
|---|
| 4691 | + case DRM_FORMAT_NV20: |
|---|
| 4692 | + if (vp->vop2->version == VOP_VERSION_RK3568 || |
|---|
| 4693 | + vp->vop2->version == VOP_VERSION_RK3588 || |
|---|
| 4694 | + vp->vop2->version == VOP_VERSION_RK3528 || |
|---|
| 4695 | + vp->vop2->version == VOP_VERSION_RK3562) { |
|---|
| 4696 | + val = src->x1 >> 16; |
|---|
| 4697 | + if (val % 8) { |
|---|
| 4698 | + src->x1 = ALIGN(val, 8) << 16; |
|---|
| 4699 | + DRM_WARN("VP%d %s src x offset[%d] must aligned as 8 pixel at NV20 fmt, and adjust to: %d\n", vp->id, win->name, val, src->x1 >> 16); |
|---|
| 4700 | + } |
|---|
| 4701 | + } else { |
|---|
| 4702 | + val = src->x1 >> 16; |
|---|
| 4703 | + if (val % 4) { |
|---|
| 4704 | + src->x1 = ALIGN(val, 4) << 16; |
|---|
| 4705 | + DRM_WARN("VP%d %s src x offset[%d] must aligned as 4 pixel at NV20 fmt, and adjust to: %d\n", vp->id, win->name, val, src->x1 >> 16); |
|---|
| 4706 | + } |
|---|
| 4707 | + } |
|---|
| 4708 | + break; |
|---|
| 4709 | + case DRM_FORMAT_NV30: |
|---|
| 4710 | + val = src->x1 >> 16; |
|---|
| 4711 | + if (val % 4) { |
|---|
| 4712 | + src->x1 = ALIGN(val, 4) << 16; |
|---|
| 4713 | + DRM_WARN("VP%d %s src x offset[%d] must aligned as 4 pixel at NV30 fmt, and adjust to: %d\n", vp->id, win->name, val, src->x1 >> 16); |
|---|
| 4714 | + } |
|---|
| 4715 | + break; |
|---|
| 4716 | + default: |
|---|
| 4717 | + return 0; |
|---|
| 4718 | + } |
|---|
| 4719 | + |
|---|
| 4720 | + return 0; |
|---|
| 4721 | +} |
|---|
| 4722 | + |
|---|
| 4551 | 4723 | static int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) |
|---|
| 4552 | 4724 | { |
|---|
| 4553 | 4725 | struct vop2_plane_state *vpstate = to_vop2_plane_state(state); |
|---|
| .. | .. |
|---|
| 4712 | 4884 | return ret; |
|---|
| 4713 | 4885 | } |
|---|
| 4714 | 4886 | |
|---|
| 4715 | | - /* |
|---|
| 4716 | | - * Src.x1 can be odd when do clip, but yuv plane start point |
|---|
| 4717 | | - * need align with 2 pixel. |
|---|
| 4718 | | - */ |
|---|
| 4719 | | - if (fb->format->is_yuv && ((state->src.x1 >> 16) % 2)) { |
|---|
| 4720 | | - DRM_ERROR("Invalid Source: Yuv format not support odd xpos\n"); |
|---|
| 4887 | + if (vop2_linear_yuv_format_check(plane, state)) |
|---|
| 4721 | 4888 | return -EINVAL; |
|---|
| 4722 | | - } |
|---|
| 4723 | 4889 | |
|---|
| 4724 | 4890 | if (fb->format->char_per_block[0] == 0) |
|---|
| 4725 | 4891 | offset = ALIGN_DOWN(src->x1 >> 16, tile_size) * fb->format->cpp[0] * tile_size; |
|---|
| .. | .. |
|---|
| 4773 | 4939 | { |
|---|
| 4774 | 4940 | struct vop2_win *win = to_vop2_win(plane); |
|---|
| 4775 | 4941 | struct vop2 *vop2 = win->vop2; |
|---|
| 4942 | + struct drm_crtc *crtc; |
|---|
| 4943 | + struct vop2_video_port *vp; |
|---|
| 4944 | + |
|---|
| 4776 | 4945 | #if defined(CONFIG_ROCKCHIP_DRM_DEBUG) |
|---|
| 4777 | 4946 | struct vop2_plane_state *vpstate = to_vop2_plane_state(plane->state); |
|---|
| 4778 | 4947 | #endif |
|---|
| .. | .. |
|---|
| 4785 | 4954 | |
|---|
| 4786 | 4955 | spin_lock(&vop2->reg_lock); |
|---|
| 4787 | 4956 | |
|---|
| 4957 | + crtc = old_state->crtc; |
|---|
| 4958 | + vp = to_vop2_video_port(crtc); |
|---|
| 4959 | + |
|---|
| 4788 | 4960 | vop2_win_disable(win, false); |
|---|
| 4789 | | - if (win->splice_win) |
|---|
| 4961 | + vp->enabled_win_mask &= ~BIT(win->phys_id); |
|---|
| 4962 | + if (win->splice_win) { |
|---|
| 4790 | 4963 | vop2_win_disable(win->splice_win, false); |
|---|
| 4964 | + vp->enabled_win_mask &= ~BIT(win->splice_win->phys_id); |
|---|
| 4965 | + } |
|---|
| 4791 | 4966 | |
|---|
| 4792 | 4967 | #if defined(CONFIG_ROCKCHIP_DRM_DEBUG) |
|---|
| 4793 | 4968 | kfree(vpstate->planlist); |
|---|
| .. | .. |
|---|
| 4957 | 5132 | uint32_t actual_w, actual_h, dsp_w, dsp_h; |
|---|
| 4958 | 5133 | uint32_t dsp_stx, dsp_sty; |
|---|
| 4959 | 5134 | uint32_t act_info, dsp_info, dsp_st; |
|---|
| 4960 | | - uint32_t format; |
|---|
| 5135 | + uint32_t format, check_size; |
|---|
| 4961 | 5136 | uint32_t afbc_format; |
|---|
| 4962 | 5137 | uint32_t rb_swap; |
|---|
| 4963 | 5138 | uint32_t uv_swap; |
|---|
| .. | .. |
|---|
| 4982 | 5157 | actual_w = drm_rect_width(src) >> 16; |
|---|
| 4983 | 5158 | actual_h = drm_rect_height(src) >> 16; |
|---|
| 4984 | 5159 | |
|---|
| 4985 | | - if (!actual_w || !actual_h) { |
|---|
| 5160 | + if (!actual_w || !actual_h || !bpp) { |
|---|
| 4986 | 5161 | vop2_win_disable(win, true); |
|---|
| 4987 | 5162 | return; |
|---|
| 4988 | 5163 | } |
|---|
| .. | .. |
|---|
| 5010 | 5185 | actual_w = dsp_w * actual_w / drm_rect_width(dst); |
|---|
| 5011 | 5186 | } |
|---|
| 5012 | 5187 | dsp_h = drm_rect_height(dst); |
|---|
| 5013 | | - if (dst->y1 + dsp_h > adjusted_mode->crtc_vdisplay) { |
|---|
| 5188 | + check_size = adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE ? adjusted_mode->vdisplay : adjusted_mode->crtc_vdisplay; |
|---|
| 5189 | + if (dst->y1 + dsp_h > check_size) { |
|---|
| 5014 | 5190 | DRM_ERROR("vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n", |
|---|
| 5015 | 5191 | vp->id, win->name, dst->y1, dsp_h, adjusted_mode->crtc_vdisplay); |
|---|
| 5016 | 5192 | dsp_h = adjusted_mode->crtc_vdisplay - dst->y1; |
|---|
| .. | .. |
|---|
| 5025 | 5201 | if (vop2->version == VOP_VERSION_RK3568) { |
|---|
| 5026 | 5202 | /* |
|---|
| 5027 | 5203 | * This is workaround solution for IC design: |
|---|
| 5028 | | - * esmart can't support scale down when actual_w % 16 == 1. |
|---|
| 5204 | + * esmart can't support scale down when actual_w % 16 == 1; |
|---|
| 5205 | + * esmart can't support scale down when dsp_w % 2 == 1; |
|---|
| 5206 | + * esmart actual_w should align as 4 pixel when is linear 10 bit yuv format; |
|---|
| 5207 | + * |
|---|
| 5208 | + * cluster actual_w should align as 4 pixel when enable afbc; |
|---|
| 5029 | 5209 | */ |
|---|
| 5030 | | - if (!(win->feature & WIN_FEATURE_AFBDC)) { |
|---|
| 5210 | + if (!vop2_cluster_window(win)) { |
|---|
| 5031 | 5211 | if (actual_w > dsp_w && (actual_w & 0xf) == 1) { |
|---|
| 5032 | | - DRM_WARN("vp%d %s act_w[%d] MODE 16 == 1\n", vp->id, win->name, actual_w); |
|---|
| 5212 | + DRM_WARN("vp%d %s act_w[%d] MODE 16 == 1 at scale down mode\n", vp->id, win->name, actual_w); |
|---|
| 5033 | 5213 | actual_w -= 1; |
|---|
| 5214 | + } |
|---|
| 5215 | + if (actual_w > dsp_w && (dsp_w & 0x1) == 1) { |
|---|
| 5216 | + DRM_WARN("vp%d %s dsp_w[%d] MODE 2 == 1 at scale down mode\n", vp->id, win->name, dsp_w); |
|---|
| 5217 | + dsp_w -= 1; |
|---|
| 5034 | 5218 | } |
|---|
| 5035 | 5219 | } |
|---|
| 5036 | 5220 | |
|---|
| 5037 | | - if (vpstate->afbc_en && actual_w % 4) { |
|---|
| 5038 | | - DRM_ERROR("vp%d %s actual_w[%d] should align as 4 pixel when enable afbc\n", |
|---|
| 5039 | | - vp->id, win->name, actual_w); |
|---|
| 5221 | + if (vop2_cluster_window(win) && actual_w % 4) { |
|---|
| 5222 | + DRM_WARN("vp%d %s actual_w[%d] should align as 4 pixel when enable afbc\n", |
|---|
| 5223 | + vp->id, win->name, actual_w); |
|---|
| 5040 | 5224 | actual_w = ALIGN_DOWN(actual_w, 4); |
|---|
| 5041 | 5225 | } |
|---|
| 5226 | + } |
|---|
| 5227 | + |
|---|
| 5228 | + if (is_linear_10bit_yuv(fb->format->format) && actual_w & 0x3) { |
|---|
| 5229 | + DRM_WARN("vp%d %s actual_w[%d] should align as 4 pixel when is linear 10 bit yuv format\n", vp->id, win->name, actual_w); |
|---|
| 5230 | + actual_w = ALIGN_DOWN(actual_w, 4); |
|---|
| 5042 | 5231 | } |
|---|
| 5043 | 5232 | |
|---|
| 5044 | 5233 | act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff); |
|---|
| .. | .. |
|---|
| 5089 | 5278 | /* AFBC pic_vir_width is count by pixel, this is different |
|---|
| 5090 | 5279 | * with WIN_VIR_STRIDE. |
|---|
| 5091 | 5280 | */ |
|---|
| 5092 | | - if (!bpp) { |
|---|
| 5093 | | - WARN(1, "bpp is zero\n"); |
|---|
| 5094 | | - bpp = 1; |
|---|
| 5095 | | - } |
|---|
| 5096 | 5281 | stride = (fb->pitches[0] << 3) / bpp; |
|---|
| 5097 | 5282 | if ((stride & 0x3f) && |
|---|
| 5098 | 5283 | (vpstate->xmirror_en || vpstate->rotate_90_en || vpstate->rotate_270_en)) |
|---|
| .. | .. |
|---|
| 5198 | 5383 | VOP_WIN_SET(vop2, win, dither_up, dither_up); |
|---|
| 5199 | 5384 | |
|---|
| 5200 | 5385 | VOP_WIN_SET(vop2, win, enable, 1); |
|---|
| 5386 | + vp->enabled_win_mask |= BIT(win->phys_id); |
|---|
| 5201 | 5387 | if (vop2_cluster_window(win)) { |
|---|
| 5202 | 5388 | lb_mode = vop2_get_cluster_lb_mode(win, vpstate); |
|---|
| 5203 | 5389 | VOP_CLUSTER_SET(vop2, win, lb_mode, lb_mode); |
|---|
| .. | .. |
|---|
| 5885 | 6071 | spin_unlock_irqrestore(&vop2->irq_lock, flags); |
|---|
| 5886 | 6072 | } |
|---|
| 5887 | 6073 | |
|---|
| 5888 | | -static int vop2_crtc_loader_protect(struct drm_crtc *crtc, bool on) |
|---|
| 6074 | +static int vop2_crtc_get_inital_acm_info(struct drm_crtc *crtc) |
|---|
| 6075 | +{ |
|---|
| 6076 | + struct vop2_video_port *vp = to_vop2_video_port(crtc); |
|---|
| 6077 | + struct vop2 *vop2 = vp->vop2; |
|---|
| 6078 | + struct post_acm *acm = &vp->acm_info; |
|---|
| 6079 | + s16 *lut_y; |
|---|
| 6080 | + s16 *lut_h; |
|---|
| 6081 | + s16 *lut_s; |
|---|
| 6082 | + u32 value; |
|---|
| 6083 | + int i; |
|---|
| 6084 | + |
|---|
| 6085 | + value = readl(vop2->acm_regs + RK3528_ACM_CTRL); |
|---|
| 6086 | + acm->acm_enable = value & 0x1; |
|---|
| 6087 | + value = readl(vop2->acm_regs + RK3528_ACM_DELTA_RANGE); |
|---|
| 6088 | + acm->y_gain = value & 0x3ff; |
|---|
| 6089 | + acm->h_gain = (value >> 10) & 0x3ff; |
|---|
| 6090 | + acm->s_gain = (value >> 20) & 0x3ff; |
|---|
| 6091 | + |
|---|
| 6092 | + lut_y = &acm->gain_lut_hy[0]; |
|---|
| 6093 | + lut_h = &acm->gain_lut_hy[ACM_GAIN_LUT_HY_LENGTH]; |
|---|
| 6094 | + lut_s = &acm->gain_lut_hy[ACM_GAIN_LUT_HY_LENGTH * 2]; |
|---|
| 6095 | + for (i = 0; i < ACM_GAIN_LUT_HY_LENGTH; i++) { |
|---|
| 6096 | + value = readl(vop2->acm_regs + RK3528_ACM_YHS_DEL_HY_SEG0 + (i << 2)); |
|---|
| 6097 | + lut_y[i] = value & 0xff; |
|---|
| 6098 | + lut_h[i] = (value >> 8) & 0xff; |
|---|
| 6099 | + lut_s[i] = (value >> 16) & 0xff; |
|---|
| 6100 | + } |
|---|
| 6101 | + |
|---|
| 6102 | + lut_y = &acm->gain_lut_hs[0]; |
|---|
| 6103 | + lut_h = &acm->gain_lut_hs[ACM_GAIN_LUT_HS_LENGTH]; |
|---|
| 6104 | + lut_s = &acm->gain_lut_hs[ACM_GAIN_LUT_HS_LENGTH * 2]; |
|---|
| 6105 | + for (i = 0; i < ACM_GAIN_LUT_HS_LENGTH; i++) { |
|---|
| 6106 | + value = readl(vop2->acm_regs + RK3528_ACM_YHS_DEL_HS_SEG0 + (i << 2)); |
|---|
| 6107 | + lut_y[i] = value & 0xff; |
|---|
| 6108 | + lut_h[i] = (value >> 8) & 0xff; |
|---|
| 6109 | + lut_s[i] = (value >> 16) & 0xff; |
|---|
| 6110 | + } |
|---|
| 6111 | + |
|---|
| 6112 | + lut_y = &acm->delta_lut_h[0]; |
|---|
| 6113 | + lut_h = &acm->delta_lut_h[ACM_DELTA_LUT_H_LENGTH]; |
|---|
| 6114 | + lut_s = &acm->delta_lut_h[ACM_DELTA_LUT_H_LENGTH * 2]; |
|---|
| 6115 | + for (i = 0; i < ACM_DELTA_LUT_H_LENGTH; i++) { |
|---|
| 6116 | + value = readl(vop2->acm_regs + RK3528_ACM_YHS_DEL_HGAIN_SEG0 + (i << 2)); |
|---|
| 6117 | + lut_y[i] = value & 0x3ff; |
|---|
| 6118 | + lut_h[i] = (value >> 12) & 0xff; |
|---|
| 6119 | + lut_s[i] = (value >> 20) & 0x3ff; |
|---|
| 6120 | + } |
|---|
| 6121 | + |
|---|
| 6122 | + return 0; |
|---|
| 6123 | +} |
|---|
| 6124 | + |
|---|
| 6125 | +static void vop2_crtc_csu_set_rate(struct drm_crtc *crtc) |
|---|
| 6126 | +{ |
|---|
| 6127 | + struct vop2_video_port *vp = to_vop2_video_port(crtc); |
|---|
| 6128 | + struct vop2 *vop2 = vp->vop2; |
|---|
| 6129 | + unsigned long aclk_rate = 0, dclk_rate = 0; |
|---|
| 6130 | + u32 csu_div = 0; |
|---|
| 6131 | + |
|---|
| 6132 | + if (!vop2->csu_aclk) |
|---|
| 6133 | + return; |
|---|
| 6134 | + |
|---|
| 6135 | + aclk_rate = clk_get_rate(vop2->aclk); |
|---|
| 6136 | + dclk_rate = clk_get_rate(vp->dclk); |
|---|
| 6137 | + if (!dclk_rate) |
|---|
| 6138 | + return; |
|---|
| 6139 | + |
|---|
| 6140 | + /* aclk >= 1/2 * dclk */ |
|---|
| 6141 | + csu_div = aclk_rate * 2 / dclk_rate; |
|---|
| 6142 | + |
|---|
| 6143 | + rockchip_csu_set_div(vop2->csu_aclk, csu_div); |
|---|
| 6144 | +} |
|---|
| 6145 | + |
|---|
| 6146 | +static int vop2_crtc_loader_protect(struct drm_crtc *crtc, bool on, void *data) |
|---|
| 5889 | 6147 | { |
|---|
| 5890 | 6148 | struct vop2_video_port *vp = to_vop2_video_port(crtc); |
|---|
| 5891 | 6149 | struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); |
|---|
| .. | .. |
|---|
| 5916 | 6174 | win->pd->vp_mask |= BIT(vp->id); |
|---|
| 5917 | 6175 | } |
|---|
| 5918 | 6176 | |
|---|
| 6177 | + vp->enabled_win_mask |= BIT(win->phys_id); |
|---|
| 5919 | 6178 | crtc_state = drm_atomic_get_crtc_state(crtc->state->state, crtc); |
|---|
| 5920 | 6179 | mode = &crtc_state->adjusted_mode; |
|---|
| 5921 | 6180 | if (mode->hdisplay > VOP2_MAX_VP_OUTPUT_WIDTH) { |
|---|
| .. | .. |
|---|
| 5928 | 6187 | splice_vp->win_mask |= BIT(splice_win->phys_id); |
|---|
| 5929 | 6188 | splice_win->vp_mask = BIT(splice_vp->id); |
|---|
| 5930 | 6189 | vop2->active_vp_mask |= BIT(splice_vp->id); |
|---|
| 6190 | + vp->enabled_win_mask |= BIT(splice_win->phys_id); |
|---|
| 5931 | 6191 | |
|---|
| 5932 | 6192 | if (splice_win->pd && |
|---|
| 5933 | 6193 | VOP_WIN_GET(vop2, splice_win, enable)) { |
|---|
| .. | .. |
|---|
| 5949 | 6209 | ext_pll->vp_mask |= BIT(vp->id); |
|---|
| 5950 | 6210 | } |
|---|
| 5951 | 6211 | drm_crtc_vblank_on(crtc); |
|---|
| 6212 | + if (is_vop3(vop2)) { |
|---|
| 6213 | + if (vp_data->feature & (VOP_FEATURE_POST_ACM)) |
|---|
| 6214 | + vop2_crtc_get_inital_acm_info(crtc); |
|---|
| 6215 | + if (data && (vp_data->feature & VOP_FEATURE_POST_CSC)) |
|---|
| 6216 | + memcpy(&vp->csc_info, data, sizeof(struct post_csc)); |
|---|
| 6217 | + } |
|---|
| 5952 | 6218 | if (private->cubic_lut[vp->id].enable) { |
|---|
| 5953 | 6219 | dma_addr_t cubic_lut_mst; |
|---|
| 5954 | 6220 | struct loader_cubic_lut *cubic_lut = &private->cubic_lut[vp->id]; |
|---|
| .. | .. |
|---|
| 5956 | 6222 | cubic_lut_mst = cubic_lut->offset + private->cubic_lut_dma_addr; |
|---|
| 5957 | 6223 | VOP_MODULE_SET(vop2, vp, cubic_lut_mst, cubic_lut_mst); |
|---|
| 5958 | 6224 | } |
|---|
| 6225 | + |
|---|
| 6226 | + vop2_crtc_csu_set_rate(crtc); |
|---|
| 5959 | 6227 | } else { |
|---|
| 5960 | 6228 | vop2_crtc_atomic_disable(crtc, NULL); |
|---|
| 5961 | 6229 | } |
|---|
| .. | .. |
|---|
| 6096 | 6364 | |
|---|
| 6097 | 6365 | /* only need to dump once at first active crtc for vop2 */ |
|---|
| 6098 | 6366 | for (i = 0; i < vop2_data->nr_vps; i++) { |
|---|
| 6099 | | - if (vop2->vps[i].rockchip_crtc.crtc.state->active) { |
|---|
| 6367 | + if (vop2->vps[i].rockchip_crtc.crtc.state && |
|---|
| 6368 | + vop2->vps[i].rockchip_crtc.crtc.state->active) { |
|---|
| 6100 | 6369 | first_active_crtc = &vop2->vps[i].rockchip_crtc.crtc; |
|---|
| 6101 | 6370 | break; |
|---|
| 6102 | 6371 | } |
|---|
| .. | .. |
|---|
| 6139 | 6408 | |
|---|
| 6140 | 6409 | /* only need to dump once at first active crtc for vop2 */ |
|---|
| 6141 | 6410 | for (i = 0; i < vop2_data->nr_vps; i++) { |
|---|
| 6142 | | - if (vop2->vps[i].rockchip_crtc.crtc.state->active) { |
|---|
| 6411 | + if (vop2->vps[i].rockchip_crtc.crtc.state && |
|---|
| 6412 | + vop2->vps[i].rockchip_crtc.crtc.state->active) { |
|---|
| 6143 | 6413 | first_active_crtc = &vop2->vps[i].rockchip_crtc.crtc; |
|---|
| 6144 | 6414 | break; |
|---|
| 6145 | 6415 | } |
|---|
| .. | .. |
|---|
| 6309 | 6579 | } else { |
|---|
| 6310 | 6580 | if (request_clock > VOP2_MAX_DCLK_RATE) |
|---|
| 6311 | 6581 | request_clock = request_clock >> 2; |
|---|
| 6312 | | - clock = clk_round_rate(vp->dclk, request_clock * 1000) / 1000; |
|---|
| 6582 | + clock = rockchip_drm_dclk_round_rate(vop2->version, vp->dclk, |
|---|
| 6583 | + request_clock * 1000) / 1000; |
|---|
| 6313 | 6584 | } |
|---|
| 6314 | 6585 | |
|---|
| 6315 | 6586 | /* |
|---|
| .. | .. |
|---|
| 6352 | 6623 | size_t bandwidth; |
|---|
| 6353 | 6624 | |
|---|
| 6354 | 6625 | if (src_width <= 0 || src_height <= 0 || dst_width <= 0 || |
|---|
| 6355 | | - dst_height <= 0) |
|---|
| 6626 | + dst_height <= 0 || !bpp) |
|---|
| 6356 | 6627 | return 0; |
|---|
| 6357 | 6628 | |
|---|
| 6358 | 6629 | bandwidth = src_width * bpp / 8; |
|---|
| 6359 | 6630 | |
|---|
| 6360 | 6631 | bandwidth = bandwidth * src_width / dst_width; |
|---|
| 6361 | 6632 | bandwidth = bandwidth * src_height / dst_height; |
|---|
| 6362 | | - if (vskiplines == 2) |
|---|
| 6633 | + if (vskiplines == 2 && vpstate->afbc_en == 0) |
|---|
| 6363 | 6634 | bandwidth /= 2; |
|---|
| 6364 | | - else if (vskiplines == 4) |
|---|
| 6635 | + else if (vskiplines == 4 && vpstate->afbc_en == 0) |
|---|
| 6365 | 6636 | bandwidth /= 4; |
|---|
| 6366 | 6637 | |
|---|
| 6367 | 6638 | return bandwidth; |
|---|
| .. | .. |
|---|
| 6455 | 6726 | |
|---|
| 6456 | 6727 | act_w = drm_rect_width(&pstate->src) >> 16; |
|---|
| 6457 | 6728 | act_h = drm_rect_height(&pstate->src) >> 16; |
|---|
| 6729 | + if (pstate->fb->format->is_yuv && (act_w >= 3840 || act_h >= 3840)) |
|---|
| 6730 | + vop_bw_info->plane_num_4k++; |
|---|
| 6731 | + |
|---|
| 6458 | 6732 | bpp = rockchip_drm_get_bpp(pstate->fb->format); |
|---|
| 6459 | 6733 | |
|---|
| 6460 | | - vop_bw_info->frame_bw_mbyte += act_w * act_h / 1000 * bpp / 8 * fps / 1000; |
|---|
| 6734 | + vop_bw_info->frame_bw_mbyte += act_w * act_h / 1000 * bpp / 8 * fps / 1000 / afbc_fac; |
|---|
| 6461 | 6735 | } |
|---|
| 6462 | 6736 | |
|---|
| 6463 | 6737 | sort(pbandwidth, cnt, sizeof(pbandwidth[0]), vop2_bandwidth_cmp, NULL); |
|---|
| .. | .. |
|---|
| 6595 | 6869 | if (mode->flags & DRM_MODE_FLAG_DBLCLK || vcstate->output_if & VOP_OUTPUT_IF_BT656) |
|---|
| 6596 | 6870 | adj_mode->crtc_clock *= 2; |
|---|
| 6597 | 6871 | |
|---|
| 6598 | | - if (vp->mcu_timing.mcu_pix_total) { |
|---|
| 6599 | | - if (vcstate->output_mode == ROCKCHIP_OUT_MODE_S888) |
|---|
| 6600 | | - adj_mode->crtc_clock *= 3; |
|---|
| 6601 | | - else if (vcstate->output_mode == ROCKCHIP_OUT_MODE_S888_DUMMY) |
|---|
| 6602 | | - adj_mode->crtc_clock *= 4; |
|---|
| 6603 | | - } |
|---|
| 6872 | + /* |
|---|
| 6873 | + * For RK3528, the path of CVBS output is like: |
|---|
| 6874 | + * VOP BT656 ENCODER -> CVBS BT656 DECODER -> CVBS ENCODER -> CVBS VDAC |
|---|
| 6875 | + * The vop2 dclk should be four times crtc_clock for CVBS sampling clock needs. |
|---|
| 6876 | + */ |
|---|
| 6877 | + if (vop2->version == VOP_VERSION_RK3528 && vcstate->output_if & VOP_OUTPUT_IF_BT656) |
|---|
| 6878 | + adj_mode->crtc_clock *= 4; |
|---|
| 6879 | + |
|---|
| 6880 | + if (vp->mcu_timing.mcu_pix_total) |
|---|
| 6881 | + adj_mode->crtc_clock *= rockchip_drm_get_cycles_per_pixel(vcstate->bus_format) * |
|---|
| 6882 | + (vp->mcu_timing.mcu_pix_total + 1); |
|---|
| 6604 | 6883 | |
|---|
| 6605 | 6884 | drm_connector_list_iter_begin(crtc->dev, &conn_iter); |
|---|
| 6606 | 6885 | drm_for_each_connector_iter(connector, &conn_iter) { |
|---|
| .. | .. |
|---|
| 6613 | 6892 | } |
|---|
| 6614 | 6893 | drm_connector_list_iter_end(&conn_iter); |
|---|
| 6615 | 6894 | |
|---|
| 6616 | | - if (adj_mode->crtc_clock <= VOP2_MAX_DCLK_RATE) |
|---|
| 6617 | | - adj_mode->crtc_clock = DIV_ROUND_UP(clk_round_rate(vp->dclk, |
|---|
| 6618 | | - adj_mode->crtc_clock * 1000), 1000); |
|---|
| 6895 | + if (adj_mode->crtc_clock <= VOP2_MAX_DCLK_RATE) { |
|---|
| 6896 | + adj_mode->crtc_clock = rockchip_drm_dclk_round_rate(vop2->version, vp->dclk, |
|---|
| 6897 | + adj_mode->crtc_clock * 1000); |
|---|
| 6898 | + adj_mode->crtc_clock = DIV_ROUND_UP(adj_mode->crtc_clock, 1000); |
|---|
| 6899 | + } |
|---|
| 6619 | 6900 | return true; |
|---|
| 6620 | 6901 | } |
|---|
| 6621 | 6902 | |
|---|
| 6622 | | -static void vop2_dither_setup(struct drm_crtc *crtc) |
|---|
| 6903 | +static void vop2_dither_setup(struct rockchip_crtc_state *vcstate, struct drm_crtc *crtc) |
|---|
| 6623 | 6904 | { |
|---|
| 6624 | | - struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); |
|---|
| 6625 | 6905 | struct vop2_video_port *vp = to_vop2_video_port(crtc); |
|---|
| 6626 | 6906 | struct vop2 *vop2 = vp->vop2; |
|---|
| 6907 | + bool pre_dither_down_en = false; |
|---|
| 6627 | 6908 | |
|---|
| 6628 | 6909 | switch (vcstate->bus_format) { |
|---|
| 6629 | 6910 | case MEDIA_BUS_FMT_RGB565_1X16: |
|---|
| 6630 | 6911 | VOP_MODULE_SET(vop2, vp, dither_down_en, 1); |
|---|
| 6631 | 6912 | VOP_MODULE_SET(vop2, vp, dither_down_mode, RGB888_TO_RGB565); |
|---|
| 6632 | | - VOP_MODULE_SET(vop2, vp, pre_dither_down_en, 1); |
|---|
| 6913 | + pre_dither_down_en = true; |
|---|
| 6633 | 6914 | break; |
|---|
| 6634 | 6915 | case MEDIA_BUS_FMT_RGB666_1X18: |
|---|
| 6635 | 6916 | case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: |
|---|
| 6636 | 6917 | case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: |
|---|
| 6637 | 6918 | VOP_MODULE_SET(vop2, vp, dither_down_en, 1); |
|---|
| 6638 | 6919 | VOP_MODULE_SET(vop2, vp, dither_down_mode, RGB888_TO_RGB666); |
|---|
| 6639 | | - VOP_MODULE_SET(vop2, vp, pre_dither_down_en, 1); |
|---|
| 6920 | + pre_dither_down_en = true; |
|---|
| 6640 | 6921 | break; |
|---|
| 6641 | 6922 | case MEDIA_BUS_FMT_YUYV8_1X16: |
|---|
| 6642 | 6923 | case MEDIA_BUS_FMT_YUV8_1X24: |
|---|
| 6643 | 6924 | case MEDIA_BUS_FMT_UYYVYY8_0_5X24: |
|---|
| 6644 | 6925 | VOP_MODULE_SET(vop2, vp, dither_down_en, 0); |
|---|
| 6645 | | - VOP_MODULE_SET(vop2, vp, pre_dither_down_en, 1); |
|---|
| 6926 | + pre_dither_down_en = true; |
|---|
| 6646 | 6927 | break; |
|---|
| 6647 | 6928 | case MEDIA_BUS_FMT_YUYV10_1X20: |
|---|
| 6648 | 6929 | case MEDIA_BUS_FMT_YUV10_1X30: |
|---|
| 6649 | 6930 | case MEDIA_BUS_FMT_UYYVYY10_0_5X30: |
|---|
| 6650 | 6931 | case MEDIA_BUS_FMT_RGB101010_1X30: |
|---|
| 6651 | 6932 | VOP_MODULE_SET(vop2, vp, dither_down_en, 0); |
|---|
| 6652 | | - VOP_MODULE_SET(vop2, vp, pre_dither_down_en, 0); |
|---|
| 6933 | + pre_dither_down_en = false; |
|---|
| 6653 | 6934 | break; |
|---|
| 6654 | 6935 | case MEDIA_BUS_FMT_RGB888_3X8: |
|---|
| 6655 | 6936 | case MEDIA_BUS_FMT_RGB888_DUMMY_4X8: |
|---|
| .. | .. |
|---|
| 6658 | 6939 | case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: |
|---|
| 6659 | 6940 | default: |
|---|
| 6660 | 6941 | VOP_MODULE_SET(vop2, vp, dither_down_en, 0); |
|---|
| 6661 | | - VOP_MODULE_SET(vop2, vp, pre_dither_down_en, 1); |
|---|
| 6942 | + pre_dither_down_en = true; |
|---|
| 6662 | 6943 | break; |
|---|
| 6663 | 6944 | } |
|---|
| 6664 | 6945 | |
|---|
| 6946 | + if (is_yuv_output(vcstate->bus_format)) |
|---|
| 6947 | + pre_dither_down_en = false; |
|---|
| 6948 | + |
|---|
| 6949 | + VOP_MODULE_SET(vop2, vp, pre_dither_down_en, pre_dither_down_en); |
|---|
| 6665 | 6950 | VOP_MODULE_SET(vop2, vp, dither_down_sel, DITHER_DOWN_ALLEGRO); |
|---|
| 6666 | 6951 | } |
|---|
| 6667 | 6952 | |
|---|
| .. | .. |
|---|
| 7266 | 7551 | dsc->enabled = true; |
|---|
| 7267 | 7552 | } |
|---|
| 7268 | 7553 | |
|---|
| 7554 | +static inline bool vop2_mark_as_left_panel(struct rockchip_crtc_state *vcstate, u32 output_if) |
|---|
| 7555 | +{ |
|---|
| 7556 | + return vcstate->output_if_left_panel & output_if; |
|---|
| 7557 | +} |
|---|
| 7558 | + |
|---|
| 7269 | 7559 | static void vop2_setup_dual_channel_if(struct drm_crtc *crtc) |
|---|
| 7270 | 7560 | { |
|---|
| 7271 | 7561 | struct vop2_video_port *vp = to_vop2_video_port(crtc); |
|---|
| 7272 | 7562 | struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); |
|---|
| 7273 | 7563 | struct vop2 *vop2 = vp->vop2; |
|---|
| 7274 | 7564 | |
|---|
| 7565 | + if (vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE) { |
|---|
| 7566 | + VOP_CTRL_SET(vop2, lvds_dual_en, 1); |
|---|
| 7567 | + VOP_CTRL_SET(vop2, lvds_dual_mode, 0); |
|---|
| 7568 | + if (vcstate->output_flags & ROCKCHIP_OUTPUT_DATA_SWAP) |
|---|
| 7569 | + VOP_CTRL_SET(vop2, lvds_dual_channel_swap, 1); |
|---|
| 7570 | + return; |
|---|
| 7571 | + } |
|---|
| 7572 | + |
|---|
| 7275 | 7573 | VOP_MODULE_SET(vop2, vp, dual_channel_en, 1); |
|---|
| 7276 | 7574 | if (vcstate->output_flags & ROCKCHIP_OUTPUT_DATA_SWAP) |
|---|
| 7277 | 7575 | VOP_MODULE_SET(vop2, vp, dual_channel_swap, 1); |
|---|
| 7278 | 7576 | |
|---|
| 7279 | | - if (vcstate->output_if & VOP_OUTPUT_IF_DP1) |
|---|
| 7577 | + if (vcstate->output_if & VOP_OUTPUT_IF_DP1 && |
|---|
| 7578 | + !vop2_mark_as_left_panel(vcstate, VOP_OUTPUT_IF_DP1)) |
|---|
| 7280 | 7579 | VOP_CTRL_SET(vop2, dp_dual_en, 1); |
|---|
| 7281 | | - else if (vcstate->output_if & VOP_OUTPUT_IF_eDP1) |
|---|
| 7580 | + else if (vcstate->output_if & VOP_OUTPUT_IF_eDP1 && |
|---|
| 7581 | + !vop2_mark_as_left_panel(vcstate, VOP_OUTPUT_IF_eDP1)) |
|---|
| 7282 | 7582 | VOP_CTRL_SET(vop2, edp_dual_en, 1); |
|---|
| 7283 | | - else if (vcstate->output_if & VOP_OUTPUT_IF_HDMI1) |
|---|
| 7583 | + else if (vcstate->output_if & VOP_OUTPUT_IF_HDMI1 && |
|---|
| 7584 | + !vop2_mark_as_left_panel(vcstate, VOP_OUTPUT_IF_HDMI1)) |
|---|
| 7284 | 7585 | VOP_CTRL_SET(vop2, hdmi_dual_en, 1); |
|---|
| 7285 | | - else if (vcstate->output_if & VOP_OUTPUT_IF_MIPI1) |
|---|
| 7586 | + else if (vcstate->output_if & VOP_OUTPUT_IF_MIPI1 && |
|---|
| 7587 | + !vop2_mark_as_left_panel(vcstate, VOP_OUTPUT_IF_MIPI1)) |
|---|
| 7286 | 7588 | VOP_CTRL_SET(vop2, mipi_dual_en, 1); |
|---|
| 7589 | + else if (vcstate->output_if & VOP_OUTPUT_IF_LVDS1) { |
|---|
| 7590 | + VOP_CTRL_SET(vop2, lvds_dual_en, 1); |
|---|
| 7591 | + VOP_CTRL_SET(vop2, lvds_dual_mode, 1); |
|---|
| 7592 | + } |
|---|
| 7287 | 7593 | } |
|---|
| 7288 | 7594 | |
|---|
| 7289 | 7595 | /* |
|---|
| .. | .. |
|---|
| 7443 | 7749 | } |
|---|
| 7444 | 7750 | } |
|---|
| 7445 | 7751 | |
|---|
| 7446 | | -static int vop2_get_vrefresh(struct vop2_video_port *vp, const struct drm_display_mode *mode) |
|---|
| 7447 | | -{ |
|---|
| 7448 | | - if (vp->mcu_timing.mcu_pix_total) |
|---|
| 7449 | | - return drm_mode_vrefresh(mode) / vp->mcu_timing.mcu_pix_total; |
|---|
| 7450 | | - else |
|---|
| 7451 | | - return drm_mode_vrefresh(mode); |
|---|
| 7452 | | -} |
|---|
| 7453 | | - |
|---|
| 7454 | 7752 | static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) |
|---|
| 7455 | 7753 | { |
|---|
| 7456 | 7754 | struct vop2_video_port *vp = to_vop2_video_port(crtc); |
|---|
| .. | .. |
|---|
| 7485 | 7783 | int ret; |
|---|
| 7486 | 7784 | |
|---|
| 7487 | 7785 | if (old_state && old_state->self_refresh_active) { |
|---|
| 7488 | | - drm_crtc_vblank_on(crtc); |
|---|
| 7489 | | - if (vop2->aclk_rate_reset) |
|---|
| 7490 | | - clk_set_rate(vop2->aclk, vop2->aclk_rate); |
|---|
| 7491 | | - vop2->aclk_rate_reset = false; |
|---|
| 7786 | + vop2_crtc_atomic_exit_psr(crtc, old_state); |
|---|
| 7492 | 7787 | |
|---|
| 7493 | 7788 | return; |
|---|
| 7494 | 7789 | } |
|---|
| .. | .. |
|---|
| 7497 | 7792 | vop2_set_system_status(vop2); |
|---|
| 7498 | 7793 | |
|---|
| 7499 | 7794 | vop2_lock(vop2); |
|---|
| 7500 | | - DRM_DEV_INFO(vop2->dev, "Update mode to %dx%d%s%d, type: %d(if:%x) for vp%d dclk: %d\n", |
|---|
| 7795 | + DRM_DEV_INFO(vop2->dev, "Update mode to %dx%d%s%d, type: %d(if:%x, flag:0x%x) for vp%d dclk: %llu\n", |
|---|
| 7501 | 7796 | hdisplay, adjusted_mode->vdisplay, interlaced ? "i" : "p", |
|---|
| 7502 | | - vop2_get_vrefresh(vp, adjusted_mode), vcstate->output_type, vcstate->output_if, |
|---|
| 7503 | | - vp->id, adjusted_mode->crtc_clock * 1000); |
|---|
| 7797 | + drm_mode_vrefresh(adjusted_mode), |
|---|
| 7798 | + vcstate->output_type, vcstate->output_if, vcstate->output_flags, |
|---|
| 7799 | + vp->id, (unsigned long long)adjusted_mode->crtc_clock * 1000); |
|---|
| 7504 | 7800 | |
|---|
| 7505 | 7801 | if (adjusted_mode->hdisplay > VOP2_MAX_VP_OUTPUT_WIDTH) { |
|---|
| 7506 | 7802 | vcstate->splice_mode = true; |
|---|
| .. | .. |
|---|
| 7510 | 7806 | splice_en = 1; |
|---|
| 7511 | 7807 | vop2->active_vp_mask |= BIT(splice_vp->id); |
|---|
| 7512 | 7808 | } |
|---|
| 7809 | + |
|---|
| 7810 | + if (vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CONNECTOR_SPLIT_MODE) |
|---|
| 7811 | + vcstate->output_flags |= ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE; |
|---|
| 7513 | 7812 | |
|---|
| 7514 | 7813 | if (vcstate->dsc_enable) { |
|---|
| 7515 | 7814 | int k = 1; |
|---|
| .. | .. |
|---|
| 7600 | 7899 | VOP_CTRL_SET(vop2, lvds_dclk_pol, dclk_inv); |
|---|
| 7601 | 7900 | } |
|---|
| 7602 | 7901 | |
|---|
| 7603 | | - if (vcstate->output_flags & (ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE | |
|---|
| 7604 | | - ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE)) { |
|---|
| 7605 | | - VOP_CTRL_SET(vop2, lvds_dual_en, 1); |
|---|
| 7606 | | - if (vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE) |
|---|
| 7607 | | - VOP_CTRL_SET(vop2, lvds_dual_mode, 1); |
|---|
| 7608 | | - if (vcstate->output_flags & ROCKCHIP_OUTPUT_DATA_SWAP) |
|---|
| 7609 | | - VOP_CTRL_SET(vop2, lvds_dual_channel_swap, 1); |
|---|
| 7610 | | - } |
|---|
| 7611 | | - |
|---|
| 7612 | 7902 | if (vcstate->output_if & VOP_OUTPUT_IF_MIPI0) { |
|---|
| 7613 | 7903 | ret = vop2_calc_cru_cfg(crtc, VOP_OUTPUT_IF_MIPI0, &if_pixclk, &if_dclk); |
|---|
| 7614 | 7904 | if (ret < 0) |
|---|
| .. | .. |
|---|
| 7652 | 7942 | } |
|---|
| 7653 | 7943 | } |
|---|
| 7654 | 7944 | |
|---|
| 7655 | | - if (vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE) |
|---|
| 7945 | + if (vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE || |
|---|
| 7946 | + vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE) |
|---|
| 7656 | 7947 | vop2_setup_dual_channel_if(crtc); |
|---|
| 7657 | 7948 | |
|---|
| 7658 | 7949 | if (vcstate->output_if & VOP_OUTPUT_IF_eDP0) { |
|---|
| .. | .. |
|---|
| 7837 | 8128 | if (ret < 0) |
|---|
| 7838 | 8129 | goto out; |
|---|
| 7839 | 8130 | |
|---|
| 7840 | | - clk_set_rate(vp->dclk, dclk->rate); |
|---|
| 8131 | + rockchip_drm_dclk_set_rate(vop2->version, vp->dclk, dclk->rate); |
|---|
| 7841 | 8132 | DRM_DEV_INFO(vop2->dev, "set %s to %ld, get %ld\n", |
|---|
| 7842 | 8133 | __clk_get_name(vp->dclk), dclk->rate, clk_get_rate(vp->dclk)); |
|---|
| 7843 | 8134 | } else { |
|---|
| 7844 | | - /* |
|---|
| 7845 | | - * For RK3528, the path of CVBS output is like: |
|---|
| 7846 | | - * VOP BT656 ENCODER -> CVBS BT656 DECODER -> CVBS ENCODER -> CVBS VDAC |
|---|
| 7847 | | - * The vop2 dclk should be four times crtc_clock for CVBS sampling clock needs. |
|---|
| 7848 | | - */ |
|---|
| 7849 | | - if (vop2->version == VOP_VERSION_RK3528 && vcstate->output_if & VOP_OUTPUT_IF_BT656) |
|---|
| 7850 | | - clk_set_rate(vp->dclk, 4 * adjusted_mode->crtc_clock * 1000); |
|---|
| 7851 | | - else |
|---|
| 7852 | | - clk_set_rate(vp->dclk, adjusted_mode->crtc_clock * 1000); |
|---|
| 8135 | + rockchip_drm_dclk_set_rate(vop2->version, vp->dclk, |
|---|
| 8136 | + adjusted_mode->crtc_clock * 1000); |
|---|
| 7853 | 8137 | } |
|---|
| 7854 | 8138 | |
|---|
| 7855 | 8139 | if (vp_data->feature & VOP_FEATURE_OVERSCAN) |
|---|
| .. | .. |
|---|
| 7878 | 8162 | if (is_vop3(vop2)) |
|---|
| 7879 | 8163 | vop3_setup_pipe_dly(vp, NULL); |
|---|
| 7880 | 8164 | |
|---|
| 8165 | + vop2_crtc_csu_set_rate(crtc); |
|---|
| 7881 | 8166 | vop2_cfg_done(crtc); |
|---|
| 7882 | 8167 | |
|---|
| 7883 | 8168 | /* |
|---|
| .. | .. |
|---|
| 7910 | 8195 | /* |
|---|
| 7911 | 8196 | * restore the lut table. |
|---|
| 7912 | 8197 | */ |
|---|
| 7913 | | - if (vp->gamma_lut_active) |
|---|
| 8198 | + if (vp->gamma_lut_active) { |
|---|
| 7914 | 8199 | vop2_crtc_load_lut(crtc); |
|---|
| 8200 | + vop2_cfg_done(crtc); |
|---|
| 8201 | + vop2_wait_for_fs_by_done_bit_status(vp); |
|---|
| 8202 | + } |
|---|
| 8203 | + |
|---|
| 8204 | + /* |
|---|
| 8205 | + * In RK3588 VOP, HDMI1/eDP1 MUX1 module's reset signal should be released |
|---|
| 8206 | + * when PD_VOP turn on. If this reset signal is not be released, the HDMI1 |
|---|
| 8207 | + * or eDP1 output interface can't work normally. |
|---|
| 8208 | + * However, If the deassert signal want to transfer to HDMI1/eDP1 MUX1 and |
|---|
| 8209 | + * take effect, it need the video port0 dclk's source clk work a few moment. |
|---|
| 8210 | + * In some cases, the video port0 dclk's source clk is disabled(now only the |
|---|
| 8211 | + * hdmi0/1 phy pll as the dclk source parent will appear) after PD_VOP turn |
|---|
| 8212 | + * on, for example, vidoe port0 dclk source select hdmi phy pll. To fix |
|---|
| 8213 | + * this issue, enable video port0 dclk for a few monent when active a video |
|---|
| 8214 | + * port which attach to eDP1/HDMI1. |
|---|
| 8215 | + */ |
|---|
| 8216 | + if (vop2->version == VOP_VERSION_RK3588) { |
|---|
| 8217 | + if (vp->id != 0 && (vp->output_if & (VOP_OUTPUT_IF_eDP1 | VOP_OUTPUT_IF_HDMI1))) { |
|---|
| 8218 | + struct vop2_video_port *vp0 = &vop2->vps[0]; |
|---|
| 8219 | + |
|---|
| 8220 | + clk_prepare_enable(vp0->dclk); |
|---|
| 8221 | + if (!clk_get_rate(vp0->dclk)) |
|---|
| 8222 | + clk_set_rate(vp0->dclk, 148500000); |
|---|
| 8223 | + udelay(20); |
|---|
| 8224 | + clk_disable_unprepare(vp0->dclk); |
|---|
| 8225 | + } |
|---|
| 8226 | + } |
|---|
| 7915 | 8227 | out: |
|---|
| 7916 | 8228 | vop2_unlock(vop2); |
|---|
| 7917 | 8229 | } |
|---|
| .. | .. |
|---|
| 9515 | 9827 | u32 value; |
|---|
| 9516 | 9828 | int i; |
|---|
| 9517 | 9829 | |
|---|
| 9518 | | - if (!acm) { |
|---|
| 9519 | | - writel(0x2, vop2->acm_regs + RK3528_ACM_CTRL); |
|---|
| 9520 | | - VOP_MODULE_SET(vop2, vp, acm_bypass_en, 1); |
|---|
| 9830 | + writel(0, vop2->acm_regs + RK3528_ACM_CTRL); |
|---|
| 9831 | + VOP_MODULE_SET(vop2, vp, acm_bypass_en, 0); |
|---|
| 9832 | + |
|---|
| 9833 | + if (!acm || !acm->acm_enable) |
|---|
| 9521 | 9834 | return; |
|---|
| 9522 | | - } |
|---|
| 9523 | 9835 | |
|---|
| 9524 | | - writel(1, vop2->acm_regs + RK3528_ACM_FETCH_START); |
|---|
| 9836 | + /* |
|---|
| 9837 | + * If acm update parameters, it need disable acm in the first frame, |
|---|
| 9838 | + * then update parameters and enable acm in second frame. |
|---|
| 9839 | + */ |
|---|
| 9840 | + vop2_cfg_done(crtc); |
|---|
| 9841 | + readx_poll_timeout(readl, vop2->acm_regs + RK3528_ACM_CTRL, value, !value, 200, 50000); |
|---|
| 9525 | 9842 | |
|---|
| 9526 | | - value = (acm->acm_enable & 0x1) + ((adjusted_mode->hdisplay & 0xfff) << 8) + |
|---|
| 9843 | + value = RK3528_ACM_ENABLE + ((adjusted_mode->hdisplay & 0xfff) << 8) + |
|---|
| 9527 | 9844 | ((adjusted_mode->vdisplay & 0xfff) << 20); |
|---|
| 9528 | 9845 | writel(value, vop2->acm_regs + RK3528_ACM_CTRL); |
|---|
| 9529 | | - VOP_MODULE_SET(vop2, vp, acm_bypass_en, acm->acm_enable ? 0 : 1); |
|---|
| 9846 | + |
|---|
| 9847 | + |
|---|
| 9848 | + writel(1, vop2->acm_regs + RK3528_ACM_FETCH_START); |
|---|
| 9530 | 9849 | |
|---|
| 9531 | 9850 | value = (acm->y_gain & 0x3ff) + ((acm->h_gain << 10) & 0xffc00) + |
|---|
| 9532 | 9851 | ((acm->s_gain << 20) & 0x3ff00000); |
|---|
| .. | .. |
|---|
| 9565 | 9884 | static void vop3_post_config(struct drm_crtc *crtc) |
|---|
| 9566 | 9885 | { |
|---|
| 9567 | 9886 | struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); |
|---|
| 9887 | + struct vop2_video_port *vp = to_vop2_video_port(crtc); |
|---|
| 9568 | 9888 | struct post_acm *acm; |
|---|
| 9569 | 9889 | struct post_csc *csc; |
|---|
| 9570 | 9890 | |
|---|
| 9571 | | - acm = vcstate->acm_lut_data ? (struct post_acm *)vcstate->acm_lut_data->data : NULL; |
|---|
| 9572 | | - vop3_post_acm_config(crtc, acm); |
|---|
| 9573 | | - |
|---|
| 9574 | 9891 | csc = vcstate->post_csc_data ? (struct post_csc *)vcstate->post_csc_data->data : NULL; |
|---|
| 9575 | | - vop3_post_csc_config(crtc, acm, csc); |
|---|
| 9892 | + if (csc && memcmp(&vp->csc_info, csc, sizeof(struct post_csc))) |
|---|
| 9893 | + memcpy(&vp->csc_info, csc, sizeof(struct post_csc)); |
|---|
| 9894 | + vop3_post_csc_config(crtc, &vp->acm_info, &vp->csc_info); |
|---|
| 9895 | + |
|---|
| 9896 | + acm = vcstate->acm_lut_data ? (struct post_acm *)vcstate->acm_lut_data->data : NULL; |
|---|
| 9897 | + |
|---|
| 9898 | + if (acm && memcmp(&vp->acm_info, acm, sizeof(struct post_acm))) { |
|---|
| 9899 | + memcpy(&vp->acm_info, acm, sizeof(struct post_acm)); |
|---|
| 9900 | + vop3_post_acm_config(crtc, &vp->acm_info); |
|---|
| 9901 | + } else if (crtc->state->active_changed) { |
|---|
| 9902 | + vop3_post_acm_config(crtc, &vp->acm_info); |
|---|
| 9903 | + } |
|---|
| 9576 | 9904 | } |
|---|
| 9577 | 9905 | |
|---|
| 9578 | 9906 | static void vop2_cfg_update(struct drm_crtc *crtc, |
|---|
| .. | .. |
|---|
| 9600 | 9928 | |
|---|
| 9601 | 9929 | vop2_post_color_swap(crtc); |
|---|
| 9602 | 9930 | |
|---|
| 9603 | | - vop2_dither_setup(crtc); |
|---|
| 9931 | + vop2_dither_setup(vcstate, crtc); |
|---|
| 9932 | + if (vcstate->splice_mode) |
|---|
| 9933 | + vop2_dither_setup(vcstate, &splice_vp->rockchip_crtc.crtc); |
|---|
| 9604 | 9934 | |
|---|
| 9605 | 9935 | VOP_MODULE_SET(vop2, vp, overlay_mode, vcstate->yuv_overlay); |
|---|
| 9606 | 9936 | |
|---|
| .. | .. |
|---|
| 9633 | 9963 | if (vp_data->feature & VOP_FEATURE_OVERSCAN) |
|---|
| 9634 | 9964 | vop2_post_config(crtc); |
|---|
| 9635 | 9965 | |
|---|
| 9966 | + spin_unlock(&vop2->reg_lock); |
|---|
| 9967 | + |
|---|
| 9636 | 9968 | if (vp_data->feature & (VOP_FEATURE_POST_ACM | VOP_FEATURE_POST_CSC)) |
|---|
| 9637 | 9969 | vop3_post_config(crtc); |
|---|
| 9638 | | - |
|---|
| 9639 | | - spin_unlock(&vop2->reg_lock); |
|---|
| 9640 | 9970 | } |
|---|
| 9641 | 9971 | |
|---|
| 9642 | 9972 | static void vop2_sleep_scan_line_time(struct vop2_video_port *vp, int scan_line) |
|---|
| .. | .. |
|---|
| 9755 | 10085 | vp->gamma_lut = crtc->state->gamma_lut->data; |
|---|
| 9756 | 10086 | vop2_crtc_atomic_gamma_set(crtc, crtc->state); |
|---|
| 9757 | 10087 | } |
|---|
| 9758 | | -#if defined(CONFIG_ROCKCHIP_DRM_CUBIC_LUT) |
|---|
| 9759 | | - if (crtc->state->cubic_lut || vp->cubic_lut) { |
|---|
| 9760 | | - if (crtc->state->cubic_lut) |
|---|
| 9761 | | - vp->cubic_lut = crtc->state->cubic_lut->data; |
|---|
| 10088 | + if (vcstate->cubic_lut_data || vp->cubic_lut) { |
|---|
| 10089 | + if (vcstate->cubic_lut_data) |
|---|
| 10090 | + vp->cubic_lut = vcstate->cubic_lut_data->data; |
|---|
| 9762 | 10091 | vop2_crtc_atomic_cubic_lut_set(crtc, crtc->state); |
|---|
| 9763 | 10092 | } |
|---|
| 9764 | | -#endif |
|---|
| 9765 | 10093 | } else { |
|---|
| 9766 | 10094 | VOP_MODULE_SET(vop2, vp, cubic_lut_update_en, 0); |
|---|
| 9767 | 10095 | } |
|---|
| .. | .. |
|---|
| 9874 | 10202 | drm_property_blob_get(vcstate->acm_lut_data); |
|---|
| 9875 | 10203 | if (vcstate->post_csc_data) |
|---|
| 9876 | 10204 | drm_property_blob_get(vcstate->post_csc_data); |
|---|
| 10205 | + if (vcstate->cubic_lut_data) |
|---|
| 10206 | + drm_property_blob_get(vcstate->cubic_lut_data); |
|---|
| 9877 | 10207 | |
|---|
| 9878 | 10208 | __drm_atomic_helper_crtc_duplicate_state(crtc, &vcstate->base); |
|---|
| 9879 | 10209 | return &vcstate->base; |
|---|
| .. | .. |
|---|
| 9888 | 10218 | drm_property_blob_put(vcstate->hdr_ext_data); |
|---|
| 9889 | 10219 | drm_property_blob_put(vcstate->acm_lut_data); |
|---|
| 9890 | 10220 | drm_property_blob_put(vcstate->post_csc_data); |
|---|
| 10221 | + drm_property_blob_put(vcstate->cubic_lut_data); |
|---|
| 9891 | 10222 | kfree(vcstate); |
|---|
| 9892 | 10223 | } |
|---|
| 9893 | 10224 | |
|---|
| .. | .. |
|---|
| 10034 | 10365 | return 0; |
|---|
| 10035 | 10366 | } |
|---|
| 10036 | 10367 | |
|---|
| 10368 | + if (property == private->cubic_lut_prop) { |
|---|
| 10369 | + *val = (vcstate->cubic_lut_data) ? vcstate->cubic_lut_data->base.id : 0; |
|---|
| 10370 | + return 0; |
|---|
| 10371 | + } |
|---|
| 10372 | + |
|---|
| 10037 | 10373 | DRM_ERROR("failed to get vop2 crtc property: %s\n", property->name); |
|---|
| 10038 | 10374 | |
|---|
| 10039 | 10375 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 10156 | 10492 | val, |
|---|
| 10157 | 10493 | sizeof(struct post_csc), -1, |
|---|
| 10158 | 10494 | &replaced); |
|---|
| 10495 | + return ret; |
|---|
| 10496 | + } |
|---|
| 10497 | + |
|---|
| 10498 | + if (property == private->cubic_lut_prop) { |
|---|
| 10499 | + ret = vop2_atomic_replace_property_blob_from_id(drm_dev, |
|---|
| 10500 | + &vcstate->cubic_lut_data, |
|---|
| 10501 | + val, |
|---|
| 10502 | + -1, sizeof(struct drm_color_lut), |
|---|
| 10503 | + &replaced); |
|---|
| 10504 | + state->color_mgmt_changed |= replaced; |
|---|
| 10159 | 10505 | return ret; |
|---|
| 10160 | 10506 | } |
|---|
| 10161 | 10507 | |
|---|
| .. | .. |
|---|
| 10660 | 11006 | return 0; |
|---|
| 10661 | 11007 | } |
|---|
| 10662 | 11008 | |
|---|
| 10663 | | -static struct drm_plane *vop2_cursor_plane_init(struct vop2_video_port *vp) |
|---|
| 11009 | +static struct drm_plane *vop2_cursor_plane_init(struct vop2_video_port *vp, u32 possible_crtcs) |
|---|
| 10664 | 11010 | { |
|---|
| 10665 | 11011 | struct vop2 *vop2 = vp->vop2; |
|---|
| 10666 | 11012 | struct drm_plane *cursor = NULL; |
|---|
| 10667 | 11013 | struct vop2_win *win; |
|---|
| 10668 | | - unsigned long possible_crtcs = 0; |
|---|
| 10669 | 11014 | |
|---|
| 10670 | 11015 | win = vop2_find_win_by_phys_id(vop2, vp->cursor_win_id); |
|---|
| 10671 | 11016 | if (win) { |
|---|
| 10672 | | - if (vop2->disable_win_move) { |
|---|
| 10673 | | - const struct vop2_data *vop2_data = vop2->data; |
|---|
| 10674 | | - struct drm_crtc *crtc = vop2_find_crtc_by_plane_mask(vop2, win->phys_id); |
|---|
| 10675 | | - |
|---|
| 10676 | | - if (crtc) |
|---|
| 10677 | | - possible_crtcs = drm_crtc_mask(crtc); |
|---|
| 10678 | | - else |
|---|
| 10679 | | - possible_crtcs = (1 << vop2_data->nr_vps) - 1; |
|---|
| 10680 | | - } |
|---|
| 10681 | | - |
|---|
| 10682 | 11017 | if (win->possible_crtcs) |
|---|
| 10683 | 11018 | possible_crtcs = win->possible_crtcs; |
|---|
| 10684 | 11019 | win->type = DRM_PLANE_TYPE_CURSOR; |
|---|
| .. | .. |
|---|
| 10790 | 11125 | { ROCKCHIP_DRM_CRTC_FEATURE_ALPHA_SCALE, "ALPHA_SCALE" }, |
|---|
| 10791 | 11126 | { ROCKCHIP_DRM_CRTC_FEATURE_HDR10, "HDR10" }, |
|---|
| 10792 | 11127 | { ROCKCHIP_DRM_CRTC_FEATURE_NEXT_HDR, "NEXT_HDR" }, |
|---|
| 11128 | + { ROCKCHIP_DRM_CRTC_FEATURE_VIVID_HDR, "VIVID_HDR" }, |
|---|
| 10793 | 11129 | }; |
|---|
| 10794 | 11130 | |
|---|
| 10795 | 11131 | if (vp_data->feature & VOP_FEATURE_ALPHA_SCALE) |
|---|
| .. | .. |
|---|
| 10798 | 11134 | feature |= BIT(ROCKCHIP_DRM_CRTC_FEATURE_HDR10); |
|---|
| 10799 | 11135 | if (vp_data->feature & VOP_FEATURE_NEXT_HDR) |
|---|
| 10800 | 11136 | feature |= BIT(ROCKCHIP_DRM_CRTC_FEATURE_NEXT_HDR); |
|---|
| 11137 | + if (vp_data->feature & VOP_FEATURE_VIVID_HDR) |
|---|
| 11138 | + feature |= BIT(ROCKCHIP_DRM_CRTC_FEATURE_VIVID_HDR); |
|---|
| 10801 | 11139 | |
|---|
| 10802 | 11140 | prop = drm_property_create_bitmask(vop2->drm_dev, |
|---|
| 10803 | 11141 | DRM_MODE_PROP_IMMUTABLE, "FEATURE", |
|---|
| .. | .. |
|---|
| 10979 | 11317 | possible_crtcs = BIT(registered_num_crtcs); |
|---|
| 10980 | 11318 | |
|---|
| 10981 | 11319 | /* |
|---|
| 10982 | | - * we assume a vp with a zere plane_mask(set from dts or bootloader) |
|---|
| 11320 | + * we assume a vp with a zero plane_mask(set from dts or bootloader) |
|---|
| 10983 | 11321 | * as unused. |
|---|
| 10984 | 11322 | */ |
|---|
| 10985 | | - if (!vp->plane_mask && bootloader_initialized) |
|---|
| 11323 | + if (!vp->plane_mask && bootloader_initialized) { |
|---|
| 11324 | + DRM_DEV_INFO(vop2->dev, "VP%d plane_mask is zero, so ignore register crtc\n", vp->id); |
|---|
| 10986 | 11325 | continue; |
|---|
| 11326 | + } |
|---|
| 10987 | 11327 | |
|---|
| 10988 | 11328 | if (vop2_soc_is_rk3566()) |
|---|
| 10989 | 11329 | soc_id = vp_data->soc_id[1]; |
|---|
| .. | .. |
|---|
| 11105 | 11445 | } |
|---|
| 11106 | 11446 | |
|---|
| 11107 | 11447 | if (vp->cursor_win_id >= 0) { |
|---|
| 11108 | | - cursor = vop2_cursor_plane_init(vp); |
|---|
| 11448 | + cursor = vop2_cursor_plane_init(vp, possible_crtcs); |
|---|
| 11109 | 11449 | if (!cursor) |
|---|
| 11110 | 11450 | DRM_WARN("failed to init cursor plane for vp%d\n", vp->id); |
|---|
| 11111 | 11451 | else |
|---|
| .. | .. |
|---|
| 11303 | 11643 | struct vop2_win *win; |
|---|
| 11304 | 11644 | struct vop2_layer *layer; |
|---|
| 11305 | 11645 | char name[DRM_PROP_NAME_LEN]; |
|---|
| 11646 | + char area_name[DRM_PROP_NAME_LEN]; |
|---|
| 11306 | 11647 | unsigned int num_wins = 0; |
|---|
| 11307 | 11648 | uint8_t plane_id = 0; |
|---|
| 11308 | 11649 | unsigned int i, j; |
|---|
| .. | .. |
|---|
| 11378 | 11719 | area->phys_id = win->phys_id; |
|---|
| 11379 | 11720 | area->area_id = j + 1; |
|---|
| 11380 | 11721 | area->plane_id = plane_id++; |
|---|
| 11381 | | - snprintf(name, min(sizeof(name), strlen(win->name)), "%s", win->name); |
|---|
| 11382 | | - snprintf(name, sizeof(name), "%s%d", name, area->area_id); |
|---|
| 11722 | + snprintf(area_name, min(sizeof(area_name), strlen(win->name)), "%s", win->name); |
|---|
| 11723 | + snprintf(name, sizeof(name), "%s%d", area_name, area->area_id); |
|---|
| 11383 | 11724 | area->name = devm_kstrdup(vop2->dev, name, GFP_KERNEL); |
|---|
| 11384 | 11725 | num_wins++; |
|---|
| 11385 | 11726 | } |
|---|
| .. | .. |
|---|
| 11673 | 12014 | return PTR_ERR(vop2->axi_rst); |
|---|
| 11674 | 12015 | } |
|---|
| 11675 | 12016 | |
|---|
| 12017 | + vop2->csu_aclk = rockchip_csu_get(dev, "aclk"); |
|---|
| 12018 | + if (IS_ERR(vop2->csu_aclk)) |
|---|
| 12019 | + vop2->csu_aclk = NULL; |
|---|
| 12020 | + |
|---|
| 11676 | 12021 | vop2->irq = platform_get_irq(pdev, 0); |
|---|
| 11677 | 12022 | if (vop2->irq < 0) { |
|---|
| 11678 | 12023 | DRM_DEV_ERROR(dev, "cannot find irq for vop2\n"); |
|---|