Lines Matching +full:rockchip +full:- +full:vop
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
4 * Author:Mark Yao <mark.yao@rock-chips.com>
45 #define VOP_WIN_SET(vop, win, name, v) \ argument
46 vop_reg_set(vop, &win->phy->name, win->base, ~0, v, #name)
47 #define VOP_SCL_SET(vop, win, name, v) \ argument
48 vop_reg_set(vop, &win->phy->scl->name, win->base, ~0, v, #name)
49 #define VOP_SCL_SET_EXT(vop, win, name, v) \ argument
50 vop_reg_set(vop, &win->phy->scl->ext->name, \
51 win->base, ~0, v, #name)
53 #define VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, name, v) \ argument
55 if (win_yuv2yuv && win_yuv2yuv->name.mask) \
56 vop_reg_set(vop, &win_yuv2yuv->name, 0, ~0, v, #name); \
59 #define VOP_WIN_YUV2YUV_COEFFICIENT_SET(vop, win_yuv2yuv, name, v) \ argument
61 if (win_yuv2yuv && win_yuv2yuv->phy->name.mask) \
62 vop_reg_set(vop, &win_yuv2yuv->phy->name, win_yuv2yuv->base, ~0, v, #name); \
65 #define VOP_INTR_SET_MASK(vop, name, mask, v) \ argument
66 vop_reg_set(vop, &vop->data->intr->name, 0, mask, v, #name)
68 #define VOP_REG_SET(vop, group, name, v) \ argument
69 vop_reg_set(vop, &vop->data->group->name, 0, ~0, v, #name)
71 #define VOP_HAS_REG(vop, group, name) \ argument
72 (!!(vop->data->group->name.mask))
74 #define VOP_INTR_SET_TYPE(vop, name, type, v) \ argument
77 for (i = 0; i < vop->data->intr->nintrs; i++) { \
78 if (vop->data->intr->intrs[i] & type) { \
83 VOP_INTR_SET_MASK(vop, name, mask, reg); \
85 #define VOP_INTR_GET_TYPE(vop, name, type) \ argument
86 vop_get_intr_type(vop, &vop->data->intr->name, type)
88 #define VOP_WIN_GET(vop, win, name) \ argument
89 vop_read_reg(vop, win->base, &win->phy->name)
92 (!!(win->phy->name.mask))
94 #define VOP_WIN_GET_YRGBADDR(vop, win) \ argument
95 vop_readl(vop, win->base + win->phy->yrgb_mst.offset)
98 ((vop_win) - (vop_win)->vop->win)
100 #define VOP_AFBC_SET(vop, name, v) \ argument
102 if ((vop)->data->afbc) \
103 vop_reg_set((vop), &(vop)->data->afbc->name, \
107 #define to_vop(x) container_of(x, struct vop, crtc)
136 struct vop *vop; member
140 struct vop { struct
149 /* protected by dev->event_lock */
163 /* physical map length of vop register */ argument
168 /* lock vop irq reg */ argument
175 /* vop AHP clk */ argument
177 /* vop dclk */ argument
179 /* vop share memory frequency */ argument
182 /* vop dclk reset */ argument
191 static inline uint32_t vop_readl(struct vop *vop, uint32_t offset) in vop_readl() argument
193 return readl(vop->regs + offset); in vop_readl()
196 static inline uint32_t vop_read_reg(struct vop *vop, uint32_t base, in vop_read_reg() argument
199 return (vop_readl(vop, base + reg->offset) >> reg->shift) & reg->mask; in vop_read_reg()
202 static void vop_reg_set(struct vop *vop, const struct vop_reg *reg, in vop_reg_set() argument
208 if (!reg || !reg->mask) { in vop_reg_set()
209 DRM_DEV_DEBUG(vop->dev, "Warning: not support %s\n", reg_name); in vop_reg_set()
213 offset = reg->offset + _offset; in vop_reg_set()
214 mask = reg->mask & _mask; in vop_reg_set()
215 shift = reg->shift; in vop_reg_set()
217 if (reg->write_mask) { in vop_reg_set()
220 uint32_t cached_val = vop->regsbak[offset >> 2]; in vop_reg_set()
223 vop->regsbak[offset >> 2] = v; in vop_reg_set()
226 if (reg->relaxed) in vop_reg_set()
227 writel_relaxed(v, vop->regs + offset); in vop_reg_set()
229 writel(v, vop->regs + offset); in vop_reg_set()
232 static inline uint32_t vop_get_intr_type(struct vop *vop, in vop_get_intr_type() argument
236 uint32_t regs = vop_read_reg(vop, 0, reg); in vop_get_intr_type()
238 for (i = 0; i < vop->data->intr->nintrs; i++) { in vop_get_intr_type()
239 if ((type & vop->data->intr->intrs[i]) && (regs & 1 << i)) in vop_get_intr_type()
240 ret |= vop->data->intr->intrs[i]; in vop_get_intr_type()
246 static inline void vop_cfg_done(struct vop *vop) in vop_cfg_done() argument
248 VOP_REG_SET(vop, common, cfg_done, 1); in vop_cfg_done()
301 return -EINVAL; in vop_convert_format()
322 return -EINVAL; in vop_convert_afbc_format()
325 return -EINVAL; in vop_convert_afbc_format()
362 static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win, in scl_vop_cal_scl_fac() argument
370 uint16_t cbcr_src_w = src_w / info->hsub; in scl_vop_cal_scl_fac()
371 uint16_t cbcr_src_h = src_h / info->vsub; in scl_vop_cal_scl_fac()
377 if (info->is_yuv) in scl_vop_cal_scl_fac()
381 DRM_DEV_ERROR(vop->dev, "Maximum dst width (3840) exceeded\n"); in scl_vop_cal_scl_fac()
385 if (!win->phy->scl->ext) { in scl_vop_cal_scl_fac()
386 VOP_SCL_SET(vop, win, scale_yrgb_x, in scl_vop_cal_scl_fac()
388 VOP_SCL_SET(vop, win, scale_yrgb_y, in scl_vop_cal_scl_fac()
391 VOP_SCL_SET(vop, win, scale_cbcr_x, in scl_vop_cal_scl_fac()
393 VOP_SCL_SET(vop, win, scale_cbcr_y, in scl_vop_cal_scl_fac()
416 VOP_SCL_SET_EXT(vop, win, lb_mode, lb_mode); in scl_vop_cal_scl_fac()
419 DRM_DEV_ERROR(vop->dev, "not allow yrgb ver scale\n"); in scl_vop_cal_scl_fac()
423 DRM_DEV_ERROR(vop->dev, "not allow cbcr ver scale\n"); in scl_vop_cal_scl_fac()
435 VOP_SCL_SET(vop, win, scale_yrgb_x, val); in scl_vop_cal_scl_fac()
438 VOP_SCL_SET(vop, win, scale_yrgb_y, val); in scl_vop_cal_scl_fac()
440 VOP_SCL_SET_EXT(vop, win, vsd_yrgb_gt4, vskiplines == 4); in scl_vop_cal_scl_fac()
441 VOP_SCL_SET_EXT(vop, win, vsd_yrgb_gt2, vskiplines == 2); in scl_vop_cal_scl_fac()
443 VOP_SCL_SET_EXT(vop, win, yrgb_hor_scl_mode, yrgb_hor_scl_mode); in scl_vop_cal_scl_fac()
444 VOP_SCL_SET_EXT(vop, win, yrgb_ver_scl_mode, yrgb_ver_scl_mode); in scl_vop_cal_scl_fac()
445 VOP_SCL_SET_EXT(vop, win, yrgb_hsd_mode, SCALE_DOWN_BIL); in scl_vop_cal_scl_fac()
446 VOP_SCL_SET_EXT(vop, win, yrgb_vsd_mode, SCALE_DOWN_BIL); in scl_vop_cal_scl_fac()
447 VOP_SCL_SET_EXT(vop, win, yrgb_vsu_mode, vsu_mode); in scl_vop_cal_scl_fac()
451 VOP_SCL_SET(vop, win, scale_cbcr_x, val); in scl_vop_cal_scl_fac()
454 VOP_SCL_SET(vop, win, scale_cbcr_y, val); in scl_vop_cal_scl_fac()
456 VOP_SCL_SET_EXT(vop, win, vsd_cbcr_gt4, vskiplines == 4); in scl_vop_cal_scl_fac()
457 VOP_SCL_SET_EXT(vop, win, vsd_cbcr_gt2, vskiplines == 2); in scl_vop_cal_scl_fac()
458 VOP_SCL_SET_EXT(vop, win, cbcr_hor_scl_mode, cbcr_hor_scl_mode); in scl_vop_cal_scl_fac()
459 VOP_SCL_SET_EXT(vop, win, cbcr_ver_scl_mode, cbcr_ver_scl_mode); in scl_vop_cal_scl_fac()
460 VOP_SCL_SET_EXT(vop, win, cbcr_hsd_mode, SCALE_DOWN_BIL); in scl_vop_cal_scl_fac()
461 VOP_SCL_SET_EXT(vop, win, cbcr_vsd_mode, SCALE_DOWN_BIL); in scl_vop_cal_scl_fac()
462 VOP_SCL_SET_EXT(vop, win, cbcr_vsu_mode, vsu_mode); in scl_vop_cal_scl_fac()
466 static void vop_dsp_hold_valid_irq_enable(struct vop *vop) in vop_dsp_hold_valid_irq_enable() argument
470 if (WARN_ON(!vop->is_enabled)) in vop_dsp_hold_valid_irq_enable()
473 spin_lock_irqsave(&vop->irq_lock, flags); in vop_dsp_hold_valid_irq_enable()
475 VOP_INTR_SET_TYPE(vop, clear, DSP_HOLD_VALID_INTR, 1); in vop_dsp_hold_valid_irq_enable()
476 VOP_INTR_SET_TYPE(vop, enable, DSP_HOLD_VALID_INTR, 1); in vop_dsp_hold_valid_irq_enable()
478 spin_unlock_irqrestore(&vop->irq_lock, flags); in vop_dsp_hold_valid_irq_enable()
481 static void vop_dsp_hold_valid_irq_disable(struct vop *vop) in vop_dsp_hold_valid_irq_disable() argument
485 if (WARN_ON(!vop->is_enabled)) in vop_dsp_hold_valid_irq_disable()
488 spin_lock_irqsave(&vop->irq_lock, flags); in vop_dsp_hold_valid_irq_disable()
490 VOP_INTR_SET_TYPE(vop, enable, DSP_HOLD_VALID_INTR, 0); in vop_dsp_hold_valid_irq_disable()
492 spin_unlock_irqrestore(&vop->irq_lock, flags); in vop_dsp_hold_valid_irq_disable()
504 * LINE_FLAG -------------------------------+
505 * FRAME_SYNC ----+ |
512 * dsp_vs_end ------------+ | | | VOP_DSP_VTOTAL_VS_END
513 * dsp_vact_start --------------+ | | VOP_DSP_VACT_ST_END
514 * dsp_vact_end ----------------------------+ | VOP_DSP_VACT_ST_END
515 * dsp_total -------------------------------------+ VOP_DSP_VTOTAL_VS_END
517 static bool vop_line_flag_irq_is_enabled(struct vop *vop) in vop_line_flag_irq_is_enabled() argument
522 spin_lock_irqsave(&vop->irq_lock, flags); in vop_line_flag_irq_is_enabled()
524 line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR); in vop_line_flag_irq_is_enabled()
526 spin_unlock_irqrestore(&vop->irq_lock, flags); in vop_line_flag_irq_is_enabled()
531 static void vop_line_flag_irq_enable(struct vop *vop) in vop_line_flag_irq_enable() argument
535 if (WARN_ON(!vop->is_enabled)) in vop_line_flag_irq_enable()
538 spin_lock_irqsave(&vop->irq_lock, flags); in vop_line_flag_irq_enable()
540 VOP_INTR_SET_TYPE(vop, clear, LINE_FLAG_INTR, 1); in vop_line_flag_irq_enable()
541 VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1); in vop_line_flag_irq_enable()
543 spin_unlock_irqrestore(&vop->irq_lock, flags); in vop_line_flag_irq_enable()
546 static void vop_line_flag_irq_disable(struct vop *vop) in vop_line_flag_irq_disable() argument
550 if (WARN_ON(!vop->is_enabled)) in vop_line_flag_irq_disable()
553 spin_lock_irqsave(&vop->irq_lock, flags); in vop_line_flag_irq_disable()
555 VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0); in vop_line_flag_irq_disable()
557 spin_unlock_irqrestore(&vop->irq_lock, flags); in vop_line_flag_irq_disable()
560 static int vop_core_clks_enable(struct vop *vop) in vop_core_clks_enable() argument
564 ret = clk_enable(vop->hclk); in vop_core_clks_enable()
568 ret = clk_enable(vop->aclk); in vop_core_clks_enable()
575 clk_disable(vop->hclk); in vop_core_clks_enable()
579 static void vop_core_clks_disable(struct vop *vop) in vop_core_clks_disable() argument
581 clk_disable(vop->aclk); in vop_core_clks_disable()
582 clk_disable(vop->hclk); in vop_core_clks_disable()
585 static void vop_win_disable(struct vop *vop, const struct vop_win *vop_win) in vop_win_disable() argument
587 const struct vop_win_data *win = vop_win->data; in vop_win_disable()
589 if (win->phy->scl && win->phy->scl->ext) { in vop_win_disable()
590 VOP_SCL_SET_EXT(vop, win, yrgb_hor_scl_mode, SCALE_NONE); in vop_win_disable()
591 VOP_SCL_SET_EXT(vop, win, yrgb_ver_scl_mode, SCALE_NONE); in vop_win_disable()
592 VOP_SCL_SET_EXT(vop, win, cbcr_hor_scl_mode, SCALE_NONE); in vop_win_disable()
593 VOP_SCL_SET_EXT(vop, win, cbcr_ver_scl_mode, SCALE_NONE); in vop_win_disable()
596 VOP_WIN_SET(vop, win, enable, 0); in vop_win_disable()
597 vop->win_enabled &= ~BIT(VOP_WIN_TO_INDEX(vop_win)); in vop_win_disable()
602 struct vop *vop = to_vop(crtc); in vop_enable() local
605 ret = pm_runtime_get_sync(vop->dev); in vop_enable()
607 DRM_DEV_ERROR(vop->dev, "failed to get pm runtime: %d\n", ret); in vop_enable()
611 ret = vop_core_clks_enable(vop); in vop_enable()
615 ret = clk_enable(vop->dclk); in vop_enable()
620 * Slave iommu shares power, irq and clock with vop. It was associated in vop_enable()
625 ret = rockchip_drm_dma_attach_device(vop->drm_dev, vop->dev); in vop_enable()
627 DRM_DEV_ERROR(vop->dev, in vop_enable()
632 spin_lock(&vop->reg_lock); in vop_enable()
633 for (i = 0; i < vop->len; i += 4) in vop_enable()
634 writel_relaxed(vop->regsbak[i / 4], vop->regs + i); in vop_enable()
641 * In the case of enable-after-PSR, we don't need to worry about this in vop_enable()
645 if (!old_state || !old_state->self_refresh_active) { in vop_enable()
646 for (i = 0; i < vop->data->win_size; i++) { in vop_enable()
647 struct vop_win *vop_win = &vop->win[i]; in vop_enable()
649 vop_win_disable(vop, vop_win); in vop_enable()
653 if (vop->data->afbc) { in vop_enable()
656 * Disable AFBC and forget there was a vop window with AFBC in vop_enable()
658 VOP_AFBC_SET(vop, enable, 0); in vop_enable()
659 s = to_rockchip_crtc_state(crtc->state); in vop_enable()
660 s->enable_afbc = false; in vop_enable()
663 vop_cfg_done(vop); in vop_enable()
665 spin_unlock(&vop->reg_lock); in vop_enable()
668 * At here, vop clock & iommu is enable, R/W vop regs would be safe. in vop_enable()
670 vop->is_enabled = true; in vop_enable()
672 spin_lock(&vop->reg_lock); in vop_enable()
674 VOP_REG_SET(vop, common, standby, 1); in vop_enable()
676 spin_unlock(&vop->reg_lock); in vop_enable()
683 clk_disable(vop->dclk); in vop_enable()
685 vop_core_clks_disable(vop); in vop_enable()
687 pm_runtime_put_sync(vop->dev); in vop_enable()
693 struct vop *vop = to_vop(crtc); in rockchip_drm_set_win_enabled() local
696 spin_lock(&vop->reg_lock); in rockchip_drm_set_win_enabled()
698 for (i = 0; i < vop->data->win_size; i++) { in rockchip_drm_set_win_enabled()
699 struct vop_win *vop_win = &vop->win[i]; in rockchip_drm_set_win_enabled()
700 const struct vop_win_data *win = vop_win->data; in rockchip_drm_set_win_enabled()
702 VOP_WIN_SET(vop, win, enable, in rockchip_drm_set_win_enabled()
703 enabled && (vop->win_enabled & BIT(i))); in rockchip_drm_set_win_enabled()
705 vop_cfg_done(vop); in rockchip_drm_set_win_enabled()
707 spin_unlock(&vop->reg_lock); in rockchip_drm_set_win_enabled()
713 struct vop *vop = to_vop(crtc); in vop_crtc_atomic_disable() local
715 WARN_ON(vop->event); in vop_crtc_atomic_disable()
717 if (crtc->state->self_refresh_active) in vop_crtc_atomic_disable()
720 mutex_lock(&vop->vop_lock); in vop_crtc_atomic_disable()
724 if (crtc->state->self_refresh_active) in vop_crtc_atomic_disable()
728 * Vop standby will take effect at end of current frame, in vop_crtc_atomic_disable()
734 reinit_completion(&vop->dsp_hold_completion); in vop_crtc_atomic_disable()
735 vop_dsp_hold_valid_irq_enable(vop); in vop_crtc_atomic_disable()
737 spin_lock(&vop->reg_lock); in vop_crtc_atomic_disable()
739 VOP_REG_SET(vop, common, standby, 1); in vop_crtc_atomic_disable()
741 spin_unlock(&vop->reg_lock); in vop_crtc_atomic_disable()
743 if (!wait_for_completion_timeout(&vop->dsp_hold_completion, in vop_crtc_atomic_disable()
745 WARN(1, "%s: timed out waiting for DSP hold", crtc->name); in vop_crtc_atomic_disable()
747 vop_dsp_hold_valid_irq_disable(vop); in vop_crtc_atomic_disable()
749 vop->is_enabled = false; in vop_crtc_atomic_disable()
752 * vop standby complete, so iommu detach is safe. in vop_crtc_atomic_disable()
754 rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev); in vop_crtc_atomic_disable()
756 clk_disable(vop->dclk); in vop_crtc_atomic_disable()
757 vop_core_clks_disable(vop); in vop_crtc_atomic_disable()
758 pm_runtime_put(vop->dev); in vop_crtc_atomic_disable()
761 mutex_unlock(&vop->vop_lock); in vop_crtc_atomic_disable()
763 if (crtc->state->event && !crtc->state->active) { in vop_crtc_atomic_disable()
764 spin_lock_irq(&crtc->dev->event_lock); in vop_crtc_atomic_disable()
765 drm_crtc_send_vblank_event(crtc, crtc->state->event); in vop_crtc_atomic_disable()
766 spin_unlock_irq(&crtc->dev->event_lock); in vop_crtc_atomic_disable()
768 crtc->state->event = NULL; in vop_crtc_atomic_disable()
802 struct drm_crtc *crtc = new_plane_state->crtc; in vop_plane_atomic_check()
804 struct drm_framebuffer *fb = new_plane_state->fb; in vop_plane_atomic_check()
806 const struct vop_win_data *win = vop_win->data; in vop_plane_atomic_check()
808 int min_scale = win->phy->scl ? FRAC_16_16(1, 8) : in vop_plane_atomic_check()
810 int max_scale = win->phy->scl ? FRAC_16_16(8, 1) : in vop_plane_atomic_check()
819 return -EINVAL; in vop_plane_atomic_check()
827 if (!new_plane_state->visible) in vop_plane_atomic_check()
830 ret = vop_convert_format(fb->format->format); in vop_plane_atomic_check()
838 if (fb->format->is_yuv && ((new_plane_state->src.x1 >> 16) % 2)) { in vop_plane_atomic_check()
840 return -EINVAL; in vop_plane_atomic_check()
843 if (fb->format->is_yuv && new_plane_state->rotation & DRM_MODE_REFLECT_Y) { in vop_plane_atomic_check()
845 return -EINVAL; in vop_plane_atomic_check()
848 if (rockchip_afbc(fb->modifier)) { in vop_plane_atomic_check()
849 struct vop *vop = to_vop(crtc); in vop_plane_atomic_check() local
851 if (!vop->data->afbc) { in vop_plane_atomic_check()
852 DRM_ERROR("vop does not support AFBC\n"); in vop_plane_atomic_check()
853 return -EINVAL; in vop_plane_atomic_check()
856 ret = vop_convert_afbc_format(fb->format->format); in vop_plane_atomic_check()
860 if (new_plane_state->src.x1 || new_plane_state->src.y1) { in vop_plane_atomic_check()
862 new_plane_state->src.x1, in vop_plane_atomic_check()
863 new_plane_state->src.y1, fb->offsets[0]); in vop_plane_atomic_check()
864 return -EINVAL; in vop_plane_atomic_check()
867 if (new_plane_state->rotation && new_plane_state->rotation != DRM_MODE_ROTATE_0) { in vop_plane_atomic_check()
869 new_plane_state->rotation); in vop_plane_atomic_check()
870 return -EINVAL; in vop_plane_atomic_check()
883 struct vop *vop = to_vop(old_state->crtc); in vop_plane_atomic_disable() local
885 if (!old_state->crtc) in vop_plane_atomic_disable()
888 spin_lock(&vop->reg_lock); in vop_plane_atomic_disable()
890 vop_win_disable(vop, vop_win); in vop_plane_atomic_disable()
892 spin_unlock(&vop->reg_lock); in vop_plane_atomic_disable()
900 struct drm_crtc *crtc = new_state->crtc; in vop_plane_atomic_update()
902 const struct vop_win_data *win = vop_win->data; in vop_plane_atomic_update()
903 const struct vop_win_yuv2yuv_data *win_yuv2yuv = vop_win->yuv2yuv_data; in vop_plane_atomic_update()
904 struct vop *vop = to_vop(new_state->crtc); in vop_plane_atomic_update() local
905 struct drm_framebuffer *fb = new_state->fb; in vop_plane_atomic_update()
909 struct drm_rect *src = &new_state->src; in vop_plane_atomic_update()
910 struct drm_rect *dest = &new_state->dst; in vop_plane_atomic_update()
919 int is_yuv = fb->format->is_yuv; in vop_plane_atomic_update()
923 * can't update plane when vop is disabled. in vop_plane_atomic_update()
928 if (WARN_ON(!vop->is_enabled)) in vop_plane_atomic_update()
931 if (!new_state->visible) { in vop_plane_atomic_update()
936 obj = fb->obj[0]; in vop_plane_atomic_update()
941 act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff); in vop_plane_atomic_update()
943 dsp_info = (drm_rect_height(dest) - 1) << 16; in vop_plane_atomic_update()
944 dsp_info |= (drm_rect_width(dest) - 1) & 0xffff; in vop_plane_atomic_update()
946 dsp_stx = dest->x1 + crtc->mode.htotal - crtc->mode.hsync_start; in vop_plane_atomic_update()
947 dsp_sty = dest->y1 + crtc->mode.vtotal - crtc->mode.vsync_start; in vop_plane_atomic_update()
950 offset = (src->x1 >> 16) * fb->format->cpp[0]; in vop_plane_atomic_update()
951 offset += (src->y1 >> 16) * fb->pitches[0]; in vop_plane_atomic_update()
952 dma_addr = rk_obj->dma_addr + offset + fb->offsets[0]; in vop_plane_atomic_update()
955 * For y-mirroring we need to move address in vop_plane_atomic_update()
958 if (new_state->rotation & DRM_MODE_REFLECT_Y) in vop_plane_atomic_update()
959 dma_addr += (actual_h - 1) * fb->pitches[0]; in vop_plane_atomic_update()
961 format = vop_convert_format(fb->format->format); in vop_plane_atomic_update()
963 spin_lock(&vop->reg_lock); in vop_plane_atomic_update()
965 if (rockchip_afbc(fb->modifier)) { in vop_plane_atomic_update()
966 int afbc_format = vop_convert_afbc_format(fb->format->format); in vop_plane_atomic_update()
968 VOP_AFBC_SET(vop, format, afbc_format | AFBC_TILE_16x16); in vop_plane_atomic_update()
969 VOP_AFBC_SET(vop, hreg_block_split, 0); in vop_plane_atomic_update()
970 VOP_AFBC_SET(vop, win_sel, VOP_WIN_TO_INDEX(vop_win)); in vop_plane_atomic_update()
971 VOP_AFBC_SET(vop, hdr_ptr, dma_addr); in vop_plane_atomic_update()
972 VOP_AFBC_SET(vop, pic_size, act_info); in vop_plane_atomic_update()
975 VOP_WIN_SET(vop, win, format, format); in vop_plane_atomic_update()
976 VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); in vop_plane_atomic_update()
977 VOP_WIN_SET(vop, win, yrgb_mst, dma_addr); in vop_plane_atomic_update()
978 VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, y2r_en, is_yuv); in vop_plane_atomic_update()
979 VOP_WIN_SET(vop, win, y_mir_en, in vop_plane_atomic_update()
980 (new_state->rotation & DRM_MODE_REFLECT_Y) ? 1 : 0); in vop_plane_atomic_update()
981 VOP_WIN_SET(vop, win, x_mir_en, in vop_plane_atomic_update()
982 (new_state->rotation & DRM_MODE_REFLECT_X) ? 1 : 0); in vop_plane_atomic_update()
985 int hsub = fb->format->hsub; in vop_plane_atomic_update()
986 int vsub = fb->format->vsub; in vop_plane_atomic_update()
987 int bpp = fb->format->cpp[1]; in vop_plane_atomic_update()
989 uv_obj = fb->obj[1]; in vop_plane_atomic_update()
992 offset = (src->x1 >> 16) * bpp / hsub; in vop_plane_atomic_update()
993 offset += (src->y1 >> 16) * fb->pitches[1] / vsub; in vop_plane_atomic_update()
995 dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1]; in vop_plane_atomic_update()
996 VOP_WIN_SET(vop, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 4)); in vop_plane_atomic_update()
997 VOP_WIN_SET(vop, win, uv_mst, dma_addr); in vop_plane_atomic_update()
1000 VOP_WIN_YUV2YUV_COEFFICIENT_SET(vop, in vop_plane_atomic_update()
1006 uv_swap = has_uv_swapped(fb->format->format); in vop_plane_atomic_update()
1007 VOP_WIN_SET(vop, win, uv_swap, uv_swap); in vop_plane_atomic_update()
1010 if (win->phy->scl) in vop_plane_atomic_update()
1011 scl_vop_cal_scl_fac(vop, win, actual_w, actual_h, in vop_plane_atomic_update()
1013 fb->format); in vop_plane_atomic_update()
1015 VOP_WIN_SET(vop, win, act_info, act_info); in vop_plane_atomic_update()
1016 VOP_WIN_SET(vop, win, dsp_info, dsp_info); in vop_plane_atomic_update()
1017 VOP_WIN_SET(vop, win, dsp_st, dsp_st); in vop_plane_atomic_update()
1019 rb_swap = has_rb_swapped(fb->format->format); in vop_plane_atomic_update()
1020 VOP_WIN_SET(vop, win, rb_swap, rb_swap); in vop_plane_atomic_update()
1025 * of the win0 framebuffer. However, blending pre-multiplied color in vop_plane_atomic_update()
1026 * with the default opaque black default background color is a no-op, in vop_plane_atomic_update()
1029 if (fb->format->has_alpha && win_index > 0) { in vop_plane_atomic_update()
1030 VOP_WIN_SET(vop, win, dst_alpha_ctl, in vop_plane_atomic_update()
1037 VOP_WIN_SET(vop, win, src_alpha_ctl, val); in vop_plane_atomic_update()
1039 VOP_WIN_SET(vop, win, alpha_pre_mul, ALPHA_SRC_PRE_MUL); in vop_plane_atomic_update()
1040 VOP_WIN_SET(vop, win, alpha_mode, ALPHA_PER_PIX); in vop_plane_atomic_update()
1041 VOP_WIN_SET(vop, win, alpha_en, 1); in vop_plane_atomic_update()
1043 VOP_WIN_SET(vop, win, src_alpha_ctl, SRC_ALPHA_EN(0)); in vop_plane_atomic_update()
1044 VOP_WIN_SET(vop, win, alpha_en, 0); in vop_plane_atomic_update()
1047 VOP_WIN_SET(vop, win, enable, 1); in vop_plane_atomic_update()
1048 vop->win_enabled |= BIT(win_index); in vop_plane_atomic_update()
1049 spin_unlock(&vop->reg_lock); in vop_plane_atomic_update()
1058 const struct vop_win_data *win = vop_win->data; in vop_plane_atomic_async_check()
1059 int min_scale = win->phy->scl ? FRAC_16_16(1, 8) : in vop_plane_atomic_async_check()
1061 int max_scale = win->phy->scl ? FRAC_16_16(8, 1) : in vop_plane_atomic_async_check()
1065 if (plane != new_plane_state->crtc->cursor) in vop_plane_atomic_async_check()
1066 return -EINVAL; in vop_plane_atomic_async_check()
1068 if (!plane->state) in vop_plane_atomic_async_check()
1069 return -EINVAL; in vop_plane_atomic_async_check()
1071 if (!plane->state->fb) in vop_plane_atomic_async_check()
1072 return -EINVAL; in vop_plane_atomic_async_check()
1076 new_plane_state->crtc); in vop_plane_atomic_async_check()
1078 crtc_state = plane->crtc->state; in vop_plane_atomic_async_check()
1080 return drm_atomic_helper_check_plane_state(plane->state, crtc_state, in vop_plane_atomic_async_check()
1090 struct vop *vop = to_vop(plane->state->crtc); in vop_plane_atomic_async_update() local
1091 struct drm_framebuffer *old_fb = plane->state->fb; in vop_plane_atomic_async_update()
1093 plane->state->crtc_x = new_state->crtc_x; in vop_plane_atomic_async_update()
1094 plane->state->crtc_y = new_state->crtc_y; in vop_plane_atomic_async_update()
1095 plane->state->crtc_h = new_state->crtc_h; in vop_plane_atomic_async_update()
1096 plane->state->crtc_w = new_state->crtc_w; in vop_plane_atomic_async_update()
1097 plane->state->src_x = new_state->src_x; in vop_plane_atomic_async_update()
1098 plane->state->src_y = new_state->src_y; in vop_plane_atomic_async_update()
1099 plane->state->src_h = new_state->src_h; in vop_plane_atomic_async_update()
1100 plane->state->src_w = new_state->src_w; in vop_plane_atomic_async_update()
1101 swap(plane->state->fb, new_state->fb); in vop_plane_atomic_async_update()
1103 if (vop->is_enabled) { in vop_plane_atomic_async_update()
1105 spin_lock(&vop->reg_lock); in vop_plane_atomic_async_update()
1106 vop_cfg_done(vop); in vop_plane_atomic_async_update()
1107 spin_unlock(&vop->reg_lock); in vop_plane_atomic_async_update()
1117 if (old_fb && plane->state->fb != old_fb) { in vop_plane_atomic_async_update()
1119 WARN_ON(drm_crtc_vblank_get(plane->state->crtc) != 0); in vop_plane_atomic_async_update()
1120 drm_flip_work_queue(&vop->fb_unref_work, old_fb); in vop_plane_atomic_async_update()
1121 set_bit(VOP_PENDING_FB_UNREF, &vop->pending); in vop_plane_atomic_async_update()
1146 struct vop *vop = to_vop(crtc); in vop_crtc_enable_vblank() local
1149 if (WARN_ON(!vop->is_enabled)) in vop_crtc_enable_vblank()
1150 return -EPERM; in vop_crtc_enable_vblank()
1152 spin_lock_irqsave(&vop->irq_lock, flags); in vop_crtc_enable_vblank()
1154 VOP_INTR_SET_TYPE(vop, clear, FS_INTR, 1); in vop_crtc_enable_vblank()
1155 VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 1); in vop_crtc_enable_vblank()
1157 spin_unlock_irqrestore(&vop->irq_lock, flags); in vop_crtc_enable_vblank()
1164 struct vop *vop = to_vop(crtc); in vop_crtc_disable_vblank() local
1167 if (WARN_ON(!vop->is_enabled)) in vop_crtc_disable_vblank()
1170 spin_lock_irqsave(&vop->irq_lock, flags); in vop_crtc_disable_vblank()
1172 VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 0); in vop_crtc_disable_vblank()
1174 spin_unlock_irqrestore(&vop->irq_lock, flags); in vop_crtc_disable_vblank()
1181 struct vop *vop = to_vop(crtc); in vop_crtc_mode_fixup() local
1189 * - DRM works in kHz. in vop_crtc_mode_fixup()
1190 * - Clock framework works in Hz. in vop_crtc_mode_fixup()
1191 * - Rockchip's clock driver picks the clock rate that is the in vop_crtc_mode_fixup()
1210 rate = clk_round_rate(vop->dclk, adjusted_mode->clock * 1000); in vop_crtc_mode_fixup()
1211 if (rate / 1000 != adjusted_mode->clock) in vop_crtc_mode_fixup()
1212 rate = clk_round_rate(vop->dclk, in vop_crtc_mode_fixup()
1213 adjusted_mode->clock * 1000 + 999); in vop_crtc_mode_fixup()
1214 adjusted_mode->clock = DIV_ROUND_UP(rate, 1000); in vop_crtc_mode_fixup()
1219 static bool vop_dsp_lut_is_enabled(struct vop *vop) in vop_dsp_lut_is_enabled() argument
1221 return vop_read_reg(vop, 0, &vop->data->common->dsp_lut_en); in vop_dsp_lut_is_enabled()
1224 static u32 vop_lut_buffer_index(struct vop *vop) in vop_lut_buffer_index() argument
1226 return vop_read_reg(vop, 0, &vop->data->common->lut_buffer_index); in vop_lut_buffer_index()
1229 static void vop_crtc_write_gamma_lut(struct vop *vop, struct drm_crtc *crtc) in vop_crtc_write_gamma_lut() argument
1231 struct drm_color_lut *lut = crtc->state->gamma_lut->data; in vop_crtc_write_gamma_lut()
1232 unsigned int i, bpc = ilog2(vop->data->lut_size); in vop_crtc_write_gamma_lut()
1234 for (i = 0; i < crtc->gamma_size; i++) { in vop_crtc_write_gamma_lut()
1240 writel(word, vop->lut_regs + i * 4); in vop_crtc_write_gamma_lut()
1244 static void vop_crtc_gamma_set(struct vop *vop, struct drm_crtc *crtc, in vop_crtc_gamma_set() argument
1247 struct drm_crtc_state *state = crtc->state; in vop_crtc_gamma_set()
1252 if (!vop->lut_regs) in vop_crtc_gamma_set()
1255 if (!state->gamma_lut || !VOP_HAS_REG(vop, common, update_gamma_lut)) { in vop_crtc_gamma_set()
1260 spin_lock(&vop->reg_lock); in vop_crtc_gamma_set()
1261 VOP_REG_SET(vop, common, dsp_lut_en, 0); in vop_crtc_gamma_set()
1262 vop_cfg_done(vop); in vop_crtc_gamma_set()
1263 spin_unlock(&vop->reg_lock); in vop_crtc_gamma_set()
1269 ret = readx_poll_timeout(vop_dsp_lut_is_enabled, vop, in vop_crtc_gamma_set()
1272 DRM_DEV_ERROR(vop->dev, "display LUT RAM enable timeout!\n"); in vop_crtc_gamma_set()
1276 if (!state->gamma_lut) in vop_crtc_gamma_set()
1283 old_idx = vop_lut_buffer_index(vop); in vop_crtc_gamma_set()
1286 spin_lock(&vop->reg_lock); in vop_crtc_gamma_set()
1287 vop_crtc_write_gamma_lut(vop, crtc); in vop_crtc_gamma_set()
1288 VOP_REG_SET(vop, common, dsp_lut_en, 1); in vop_crtc_gamma_set()
1289 VOP_REG_SET(vop, common, update_gamma_lut, 1); in vop_crtc_gamma_set()
1290 vop_cfg_done(vop); in vop_crtc_gamma_set()
1291 spin_unlock(&vop->reg_lock); in vop_crtc_gamma_set()
1293 if (VOP_HAS_REG(vop, common, update_gamma_lut)) { in vop_crtc_gamma_set()
1294 ret = readx_poll_timeout(vop_lut_buffer_index, vop, in vop_crtc_gamma_set()
1297 DRM_DEV_ERROR(vop->dev, "gamma LUT update timeout!\n"); in vop_crtc_gamma_set()
1305 spin_lock(&vop->reg_lock); in vop_crtc_gamma_set()
1306 VOP_REG_SET(vop, common, update_gamma_lut, 0); in vop_crtc_gamma_set()
1307 spin_unlock(&vop->reg_lock); in vop_crtc_gamma_set()
1318 struct vop *vop = to_vop(crtc); in vop_crtc_atomic_begin() local
1324 if (crtc_state->color_mgmt_changed && in vop_crtc_atomic_begin()
1325 !crtc_state->active_changed) in vop_crtc_atomic_begin()
1326 vop_crtc_gamma_set(vop, crtc, old_crtc_state); in vop_crtc_atomic_begin()
1334 struct vop *vop = to_vop(crtc); in vop_crtc_atomic_enable() local
1335 const struct vop_data *vop_data = vop->data; in vop_crtc_atomic_enable()
1336 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); in vop_crtc_atomic_enable()
1337 struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; in vop_crtc_atomic_enable()
1338 u16 hsync_len = adjusted_mode->hsync_end - adjusted_mode->hsync_start; in vop_crtc_atomic_enable()
1339 u16 hdisplay = adjusted_mode->hdisplay; in vop_crtc_atomic_enable()
1340 u16 htotal = adjusted_mode->htotal; in vop_crtc_atomic_enable()
1341 u16 hact_st = adjusted_mode->htotal - adjusted_mode->hsync_start; in vop_crtc_atomic_enable()
1343 u16 vdisplay = adjusted_mode->vdisplay; in vop_crtc_atomic_enable()
1344 u16 vtotal = adjusted_mode->vtotal; in vop_crtc_atomic_enable()
1345 u16 vsync_len = adjusted_mode->vsync_end - adjusted_mode->vsync_start; in vop_crtc_atomic_enable()
1346 u16 vact_st = adjusted_mode->vtotal - adjusted_mode->vsync_start; in vop_crtc_atomic_enable()
1349 int dither_bpc = s->output_bpc ? s->output_bpc : 10; in vop_crtc_atomic_enable()
1352 if (old_state && old_state->self_refresh_active) { in vop_crtc_atomic_enable()
1358 mutex_lock(&vop->vop_lock); in vop_crtc_atomic_enable()
1360 WARN_ON(vop->event); in vop_crtc_atomic_enable()
1364 mutex_unlock(&vop->vop_lock); in vop_crtc_atomic_enable()
1365 DRM_DEV_ERROR(vop->dev, "Failed to enable vop (%d)\n", ret); in vop_crtc_atomic_enable()
1368 pin_pol = (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) ? in vop_crtc_atomic_enable()
1370 pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) ? in vop_crtc_atomic_enable()
1372 VOP_REG_SET(vop, output, pin_pol, pin_pol); in vop_crtc_atomic_enable()
1373 VOP_REG_SET(vop, output, mipi_dual_channel_en, 0); in vop_crtc_atomic_enable()
1375 switch (s->output_type) { in vop_crtc_atomic_enable()
1377 VOP_REG_SET(vop, output, rgb_dclk_pol, 1); in vop_crtc_atomic_enable()
1378 VOP_REG_SET(vop, output, rgb_pin_pol, pin_pol); in vop_crtc_atomic_enable()
1379 VOP_REG_SET(vop, output, rgb_en, 1); in vop_crtc_atomic_enable()
1382 VOP_REG_SET(vop, output, edp_dclk_pol, 1); in vop_crtc_atomic_enable()
1383 VOP_REG_SET(vop, output, edp_pin_pol, pin_pol); in vop_crtc_atomic_enable()
1384 VOP_REG_SET(vop, output, edp_en, 1); in vop_crtc_atomic_enable()
1387 VOP_REG_SET(vop, output, hdmi_dclk_pol, 1); in vop_crtc_atomic_enable()
1388 VOP_REG_SET(vop, output, hdmi_pin_pol, pin_pol); in vop_crtc_atomic_enable()
1389 VOP_REG_SET(vop, output, hdmi_en, 1); in vop_crtc_atomic_enable()
1392 VOP_REG_SET(vop, output, mipi_dclk_pol, 1); in vop_crtc_atomic_enable()
1393 VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol); in vop_crtc_atomic_enable()
1394 VOP_REG_SET(vop, output, mipi_en, 1); in vop_crtc_atomic_enable()
1395 VOP_REG_SET(vop, output, mipi_dual_channel_en, in vop_crtc_atomic_enable()
1396 !!(s->output_flags & ROCKCHIP_OUTPUT_DSI_DUAL)); in vop_crtc_atomic_enable()
1399 VOP_REG_SET(vop, output, dp_dclk_pol, 0); in vop_crtc_atomic_enable()
1400 VOP_REG_SET(vop, output, dp_pin_pol, pin_pol); in vop_crtc_atomic_enable()
1401 VOP_REG_SET(vop, output, dp_en, 1); in vop_crtc_atomic_enable()
1404 DRM_DEV_ERROR(vop->dev, "unsupported connector_type [%d]\n", in vop_crtc_atomic_enable()
1405 s->output_type); in vop_crtc_atomic_enable()
1409 * if vop is not support RGB10 output, need force RGB10 to RGB888. in vop_crtc_atomic_enable()
1411 if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && in vop_crtc_atomic_enable()
1412 !(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10)) in vop_crtc_atomic_enable()
1413 s->output_mode = ROCKCHIP_OUT_MODE_P888; in vop_crtc_atomic_enable()
1415 if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && dither_bpc <= 8) in vop_crtc_atomic_enable()
1416 VOP_REG_SET(vop, common, pre_dither_down, 1); in vop_crtc_atomic_enable()
1418 VOP_REG_SET(vop, common, pre_dither_down, 0); in vop_crtc_atomic_enable()
1421 VOP_REG_SET(vop, common, dither_down_sel, DITHER_DOWN_ALLEGRO); in vop_crtc_atomic_enable()
1422 VOP_REG_SET(vop, common, dither_down_mode, RGB888_TO_RGB666); in vop_crtc_atomic_enable()
1423 VOP_REG_SET(vop, common, dither_down_en, 1); in vop_crtc_atomic_enable()
1425 VOP_REG_SET(vop, common, dither_down_en, 0); in vop_crtc_atomic_enable()
1428 VOP_REG_SET(vop, common, out_mode, s->output_mode); in vop_crtc_atomic_enable()
1430 VOP_REG_SET(vop, modeset, htotal_pw, (htotal << 16) | hsync_len); in vop_crtc_atomic_enable()
1433 VOP_REG_SET(vop, modeset, hact_st_end, val); in vop_crtc_atomic_enable()
1434 VOP_REG_SET(vop, modeset, hpost_st_end, val); in vop_crtc_atomic_enable()
1436 VOP_REG_SET(vop, modeset, vtotal_pw, (vtotal << 16) | vsync_len); in vop_crtc_atomic_enable()
1439 VOP_REG_SET(vop, modeset, vact_st_end, val); in vop_crtc_atomic_enable()
1440 VOP_REG_SET(vop, modeset, vpost_st_end, val); in vop_crtc_atomic_enable()
1442 VOP_REG_SET(vop, intr, line_flag_num[0], vact_end); in vop_crtc_atomic_enable()
1444 clk_set_rate(vop->dclk, adjusted_mode->clock * 1000); in vop_crtc_atomic_enable()
1446 VOP_REG_SET(vop, common, standby, 0); in vop_crtc_atomic_enable()
1447 mutex_unlock(&vop->vop_lock); in vop_crtc_atomic_enable()
1452 * which means the LUT internal memory needs to be re-written. in vop_crtc_atomic_enable()
1454 if (crtc->state->gamma_lut) in vop_crtc_atomic_enable()
1455 vop_crtc_gamma_set(vop, crtc, old_state); in vop_crtc_atomic_enable()
1458 static bool vop_fs_irq_is_pending(struct vop *vop) in vop_fs_irq_is_pending() argument
1460 return VOP_INTR_GET_TYPE(vop, status, FS_INTR); in vop_fs_irq_is_pending()
1463 static void vop_wait_for_irq_handler(struct vop *vop) in vop_wait_for_irq_handler() argument
1476 ret = readx_poll_timeout_atomic(vop_fs_irq_is_pending, vop, pending, in vop_wait_for_irq_handler()
1479 DRM_DEV_ERROR(vop->dev, "VOP vblank IRQ stuck for 10 ms\n"); in vop_wait_for_irq_handler()
1481 synchronize_irq(vop->irq); in vop_wait_for_irq_handler()
1489 struct vop *vop = to_vop(crtc); in vop_crtc_atomic_check() local
1495 if (vop->lut_regs && crtc_state->color_mgmt_changed && in vop_crtc_atomic_check()
1496 crtc_state->gamma_lut) { in vop_crtc_atomic_check()
1499 len = drm_color_lut_size(crtc_state->gamma_lut); in vop_crtc_atomic_check()
1500 if (len != crtc->gamma_size) { in vop_crtc_atomic_check()
1502 len, crtc->gamma_size); in vop_crtc_atomic_check()
1503 return -EINVAL; in vop_crtc_atomic_check()
1509 drm_atomic_get_plane_state(crtc_state->state, plane); in vop_crtc_atomic_check()
1512 plane->name); in vop_crtc_atomic_check()
1516 if (drm_is_afbc(plane_state->fb->modifier)) in vop_crtc_atomic_check()
1522 return -EINVAL; in vop_crtc_atomic_check()
1526 s->enable_afbc = afbc_planes > 0; in vop_crtc_atomic_check()
1536 struct drm_atomic_state *old_state = old_crtc_state->state; in vop_crtc_atomic_flush()
1538 struct vop *vop = to_vop(crtc); in vop_crtc_atomic_flush() local
1543 if (WARN_ON(!vop->is_enabled)) in vop_crtc_atomic_flush()
1546 spin_lock(&vop->reg_lock); in vop_crtc_atomic_flush()
1549 s = to_rockchip_crtc_state(crtc->state); in vop_crtc_atomic_flush()
1550 VOP_AFBC_SET(vop, enable, s->enable_afbc); in vop_crtc_atomic_flush()
1551 vop_cfg_done(vop); in vop_crtc_atomic_flush()
1553 spin_unlock(&vop->reg_lock); in vop_crtc_atomic_flush()
1560 vop_wait_for_irq_handler(vop); in vop_crtc_atomic_flush()
1562 spin_lock_irq(&crtc->dev->event_lock); in vop_crtc_atomic_flush()
1563 if (crtc->state->event) { in vop_crtc_atomic_flush()
1565 WARN_ON(vop->event); in vop_crtc_atomic_flush()
1567 vop->event = crtc->state->event; in vop_crtc_atomic_flush()
1568 crtc->state->event = NULL; in vop_crtc_atomic_flush()
1570 spin_unlock_irq(&crtc->dev->event_lock); in vop_crtc_atomic_flush()
1574 if (!old_plane_state->fb) in vop_crtc_atomic_flush()
1577 if (old_plane_state->fb == new_plane_state->fb) in vop_crtc_atomic_flush()
1580 drm_framebuffer_get(old_plane_state->fb); in vop_crtc_atomic_flush()
1582 drm_flip_work_queue(&vop->fb_unref_work, old_plane_state->fb); in vop_crtc_atomic_flush()
1583 set_bit(VOP_PENDING_FB_UNREF, &vop->pending); in vop_crtc_atomic_flush()
1605 if (WARN_ON(!crtc->state)) in vop_crtc_duplicate_state()
1612 __drm_atomic_helper_crtc_duplicate_state(crtc, &rockchip_state->base); in vop_crtc_duplicate_state()
1613 return &rockchip_state->base; in vop_crtc_duplicate_state()
1621 __drm_atomic_helper_crtc_destroy_state(&s->base); in vop_crtc_destroy_state()
1630 if (crtc->state) in vop_crtc_reset()
1631 vop_crtc_destroy_state(crtc, crtc->state); in vop_crtc_reset()
1633 __drm_atomic_helper_crtc_reset(crtc, &crtc_state->base); in vop_crtc_reset()
1637 static struct drm_connector *vop_get_edp_connector(struct vop *vop) in vop_get_edp_connector() argument
1642 drm_connector_list_iter_begin(vop->drm_dev, &conn_iter); in vop_get_edp_connector()
1644 if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { in vop_get_edp_connector()
1657 struct vop *vop = to_vop(crtc); in vop_crtc_set_crc_source() local
1661 connector = vop_get_edp_connector(vop); in vop_crtc_set_crc_source()
1663 return -EINVAL; in vop_crtc_set_crc_source()
1670 ret = -EINVAL; in vop_crtc_set_crc_source()
1680 return -EINVAL; in vop_crtc_verify_crc_source()
1690 return -ENODEV; in vop_crtc_set_crc_source()
1697 return -ENODEV; in vop_crtc_verify_crc_source()
1716 struct vop *vop = container_of(work, struct vop, fb_unref_work); in vop_fb_unref_worker() local
1719 drm_crtc_vblank_put(&vop->crtc); in vop_fb_unref_worker()
1723 static void vop_handle_vblank(struct vop *vop) in vop_handle_vblank() argument
1725 struct drm_device *drm = vop->drm_dev; in vop_handle_vblank()
1726 struct drm_crtc *crtc = &vop->crtc; in vop_handle_vblank()
1728 spin_lock(&drm->event_lock); in vop_handle_vblank()
1729 if (vop->event) { in vop_handle_vblank()
1730 drm_crtc_send_vblank_event(crtc, vop->event); in vop_handle_vblank()
1732 vop->event = NULL; in vop_handle_vblank()
1734 spin_unlock(&drm->event_lock); in vop_handle_vblank()
1736 if (test_and_clear_bit(VOP_PENDING_FB_UNREF, &vop->pending)) in vop_handle_vblank()
1737 drm_flip_work_commit(&vop->fb_unref_work, system_unbound_wq); in vop_handle_vblank()
1742 struct vop *vop = data; in vop_isr() local
1743 struct drm_crtc *crtc = &vop->crtc; in vop_isr()
1748 * The irq is shared with the iommu. If the runtime-pm state of the in vop_isr()
1749 * vop-device is disabled the irq has to be targeted at the iommu. in vop_isr()
1751 if (!pm_runtime_get_if_in_use(vop->dev)) in vop_isr()
1754 if (vop_core_clks_enable(vop)) { in vop_isr()
1755 DRM_DEV_ERROR_RATELIMITED(vop->dev, "couldn't enable clocks\n"); in vop_isr()
1763 spin_lock(&vop->irq_lock); in vop_isr()
1765 active_irqs = VOP_INTR_GET_TYPE(vop, status, INTR_MASK); in vop_isr()
1768 VOP_INTR_SET_TYPE(vop, clear, active_irqs, 1); in vop_isr()
1770 spin_unlock(&vop->irq_lock); in vop_isr()
1772 /* This is expected for vop iommu irqs, since the irq is shared */ in vop_isr()
1777 complete(&vop->dsp_hold_completion); in vop_isr()
1783 complete(&vop->line_flag_completion); in vop_isr()
1790 vop_handle_vblank(vop); in vop_isr()
1797 DRM_DEV_ERROR(vop->dev, "Unknown VOP IRQs: %#02x\n", in vop_isr()
1801 vop_core_clks_disable(vop); in vop_isr()
1803 pm_runtime_put(vop->dev); in vop_isr()
1819 static int vop_create_crtc(struct vop *vop) in vop_create_crtc() argument
1821 const struct vop_data *vop_data = vop->data; in vop_create_crtc()
1822 struct device *dev = vop->dev; in vop_create_crtc()
1823 struct drm_device *drm_dev = vop->drm_dev; in vop_create_crtc()
1825 struct drm_crtc *crtc = &vop->crtc; in vop_create_crtc()
1835 for (i = 0; i < vop_data->win_size; i++) { in vop_create_crtc()
1836 struct vop_win *vop_win = &vop->win[i]; in vop_create_crtc()
1837 const struct vop_win_data *win_data = vop_win->data; in vop_create_crtc()
1839 if (win_data->type != DRM_PLANE_TYPE_PRIMARY && in vop_create_crtc()
1840 win_data->type != DRM_PLANE_TYPE_CURSOR) in vop_create_crtc()
1843 ret = drm_universal_plane_init(vop->drm_dev, &vop_win->base, in vop_create_crtc()
1845 win_data->phy->data_formats, in vop_create_crtc()
1846 win_data->phy->nformats, in vop_create_crtc()
1847 win_data->phy->format_modifiers, in vop_create_crtc()
1848 win_data->type, NULL); in vop_create_crtc()
1850 DRM_DEV_ERROR(vop->dev, "failed to init plane %d\n", in vop_create_crtc()
1855 plane = &vop_win->base; in vop_create_crtc()
1858 if (plane->type == DRM_PLANE_TYPE_PRIMARY) in vop_create_crtc()
1860 else if (plane->type == DRM_PLANE_TYPE_CURSOR) in vop_create_crtc()
1870 if (vop->lut_regs) { in vop_create_crtc()
1871 drm_mode_crtc_set_gamma_size(crtc, vop_data->lut_size); in vop_create_crtc()
1872 drm_crtc_enable_color_mgmt(crtc, 0, false, vop_data->lut_size); in vop_create_crtc()
1879 for (i = 0; i < vop_data->win_size; i++) { in vop_create_crtc()
1880 struct vop_win *vop_win = &vop->win[i]; in vop_create_crtc()
1881 const struct vop_win_data *win_data = vop_win->data; in vop_create_crtc()
1884 if (win_data->type != DRM_PLANE_TYPE_OVERLAY) in vop_create_crtc()
1887 ret = drm_universal_plane_init(vop->drm_dev, &vop_win->base, in vop_create_crtc()
1890 win_data->phy->data_formats, in vop_create_crtc()
1891 win_data->phy->nformats, in vop_create_crtc()
1892 win_data->phy->format_modifiers, in vop_create_crtc()
1893 win_data->type, NULL); in vop_create_crtc()
1895 DRM_DEV_ERROR(vop->dev, "failed to init overlay %d\n", in vop_create_crtc()
1899 drm_plane_helper_add(&vop_win->base, &plane_helper_funcs); in vop_create_crtc()
1900 vop_plane_add_properties(&vop_win->base, win_data); in vop_create_crtc()
1903 port = of_get_child_by_name(dev->of_node, "port"); in vop_create_crtc()
1905 DRM_DEV_ERROR(vop->dev, "no port node found in %pOF\n", in vop_create_crtc()
1906 dev->of_node); in vop_create_crtc()
1907 ret = -ENOENT; in vop_create_crtc()
1911 drm_flip_work_init(&vop->fb_unref_work, "fb_unref", in vop_create_crtc()
1914 init_completion(&vop->dsp_hold_completion); in vop_create_crtc()
1915 init_completion(&vop->line_flag_completion); in vop_create_crtc()
1916 crtc->port = port; in vop_create_crtc()
1920 DRM_DEV_DEBUG_KMS(vop->dev, in vop_create_crtc()
1922 crtc->name, ret); in vop_create_crtc()
1929 list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list, in vop_create_crtc()
1935 static void vop_destroy_crtc(struct vop *vop) in vop_destroy_crtc() argument
1937 struct drm_crtc *crtc = &vop->crtc; in vop_destroy_crtc()
1938 struct drm_device *drm_dev = vop->drm_dev; in vop_destroy_crtc()
1943 of_node_put(crtc->port); in vop_destroy_crtc()
1948 * The planes are "&vop->win[i].base". That means the memory is in vop_destroy_crtc()
1949 * all part of the big "struct vop" chunk of memory. That memory in vop_destroy_crtc()
1953 list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list, in vop_destroy_crtc()
1962 drm_flip_work_cleanup(&vop->fb_unref_work); in vop_destroy_crtc()
1965 static int vop_initial(struct vop *vop) in vop_initial() argument
1970 vop->hclk = devm_clk_get(vop->dev, "hclk_vop"); in vop_initial()
1971 if (IS_ERR(vop->hclk)) { in vop_initial()
1972 DRM_DEV_ERROR(vop->dev, "failed to get hclk source\n"); in vop_initial()
1973 return PTR_ERR(vop->hclk); in vop_initial()
1975 vop->aclk = devm_clk_get(vop->dev, "aclk_vop"); in vop_initial()
1976 if (IS_ERR(vop->aclk)) { in vop_initial()
1977 DRM_DEV_ERROR(vop->dev, "failed to get aclk source\n"); in vop_initial()
1978 return PTR_ERR(vop->aclk); in vop_initial()
1980 vop->dclk = devm_clk_get(vop->dev, "dclk_vop"); in vop_initial()
1981 if (IS_ERR(vop->dclk)) { in vop_initial()
1982 DRM_DEV_ERROR(vop->dev, "failed to get dclk source\n"); in vop_initial()
1983 return PTR_ERR(vop->dclk); in vop_initial()
1986 ret = pm_runtime_get_sync(vop->dev); in vop_initial()
1988 DRM_DEV_ERROR(vop->dev, "failed to get pm runtime: %d\n", ret); in vop_initial()
1992 ret = clk_prepare(vop->dclk); in vop_initial()
1994 DRM_DEV_ERROR(vop->dev, "failed to prepare dclk\n"); in vop_initial()
1998 /* Enable both the hclk and aclk to setup the vop */ in vop_initial()
1999 ret = clk_prepare_enable(vop->hclk); in vop_initial()
2001 DRM_DEV_ERROR(vop->dev, "failed to prepare/enable hclk\n"); in vop_initial()
2005 ret = clk_prepare_enable(vop->aclk); in vop_initial()
2007 DRM_DEV_ERROR(vop->dev, "failed to prepare/enable aclk\n"); in vop_initial()
2012 * do hclk_reset, reset all vop registers. in vop_initial()
2014 ahb_rst = devm_reset_control_get(vop->dev, "ahb"); in vop_initial()
2016 DRM_DEV_ERROR(vop->dev, "failed to get ahb reset\n"); in vop_initial()
2024 VOP_INTR_SET_TYPE(vop, clear, INTR_MASK, 1); in vop_initial()
2025 VOP_INTR_SET_TYPE(vop, enable, INTR_MASK, 0); in vop_initial()
2027 for (i = 0; i < vop->len; i += sizeof(u32)) in vop_initial()
2028 vop->regsbak[i / 4] = readl_relaxed(vop->regs + i); in vop_initial()
2030 VOP_REG_SET(vop, misc, global_regdone_en, 1); in vop_initial()
2031 VOP_REG_SET(vop, common, dsp_blank, 0); in vop_initial()
2033 for (i = 0; i < vop->data->win_size; i++) { in vop_initial()
2034 struct vop_win *vop_win = &vop->win[i]; in vop_initial()
2035 const struct vop_win_data *win = vop_win->data; in vop_initial()
2038 VOP_WIN_SET(vop, win, channel, (channel + 1) << 4 | channel); in vop_initial()
2039 vop_win_disable(vop, vop_win); in vop_initial()
2040 VOP_WIN_SET(vop, win, gate, 1); in vop_initial()
2043 vop_cfg_done(vop); in vop_initial()
2048 vop->dclk_rst = devm_reset_control_get(vop->dev, "dclk"); in vop_initial()
2049 if (IS_ERR(vop->dclk_rst)) { in vop_initial()
2050 DRM_DEV_ERROR(vop->dev, "failed to get dclk reset\n"); in vop_initial()
2051 ret = PTR_ERR(vop->dclk_rst); in vop_initial()
2054 reset_control_assert(vop->dclk_rst); in vop_initial()
2056 reset_control_deassert(vop->dclk_rst); in vop_initial()
2058 clk_disable(vop->hclk); in vop_initial()
2059 clk_disable(vop->aclk); in vop_initial()
2061 vop->is_enabled = false; in vop_initial()
2063 pm_runtime_put_sync(vop->dev); in vop_initial()
2068 clk_disable_unprepare(vop->aclk); in vop_initial()
2070 clk_disable_unprepare(vop->hclk); in vop_initial()
2072 clk_unprepare(vop->dclk); in vop_initial()
2074 pm_runtime_put_sync(vop->dev); in vop_initial()
2079 * Initialize the vop->win array elements.
2081 static void vop_win_init(struct vop *vop) in vop_win_init() argument
2083 const struct vop_data *vop_data = vop->data; in vop_win_init()
2086 for (i = 0; i < vop_data->win_size; i++) { in vop_win_init()
2087 struct vop_win *vop_win = &vop->win[i]; in vop_win_init()
2088 const struct vop_win_data *win_data = &vop_data->win[i]; in vop_win_init()
2090 vop_win->data = win_data; in vop_win_init()
2091 vop_win->vop = vop; in vop_win_init()
2093 if (vop_data->win_yuv2yuv) in vop_win_init()
2094 vop_win->yuv2yuv_data = &vop_data->win_yuv2yuv[i]; in vop_win_init()
2110 struct vop *vop = to_vop(crtc); in rockchip_drm_wait_vact_end() local
2114 if (!crtc || !vop->is_enabled) in rockchip_drm_wait_vact_end()
2115 return -ENODEV; in rockchip_drm_wait_vact_end()
2117 mutex_lock(&vop->vop_lock); in rockchip_drm_wait_vact_end()
2119 ret = -EINVAL; in rockchip_drm_wait_vact_end()
2123 if (vop_line_flag_irq_is_enabled(vop)) { in rockchip_drm_wait_vact_end()
2124 ret = -EBUSY; in rockchip_drm_wait_vact_end()
2128 reinit_completion(&vop->line_flag_completion); in rockchip_drm_wait_vact_end()
2129 vop_line_flag_irq_enable(vop); in rockchip_drm_wait_vact_end()
2131 jiffies_left = wait_for_completion_timeout(&vop->line_flag_completion, in rockchip_drm_wait_vact_end()
2133 vop_line_flag_irq_disable(vop); in rockchip_drm_wait_vact_end()
2136 DRM_DEV_ERROR(vop->dev, "Timeout waiting for IRQ\n"); in rockchip_drm_wait_vact_end()
2137 ret = -ETIMEDOUT; in rockchip_drm_wait_vact_end()
2142 mutex_unlock(&vop->vop_lock); in rockchip_drm_wait_vact_end()
2152 struct vop *vop; in vop_bind() local
2158 return -ENODEV; in vop_bind()
2160 /* Allocate vop struct and its vop_win array */ in vop_bind()
2161 vop = devm_kzalloc(dev, struct_size(vop, win, vop_data->win_size), in vop_bind()
2163 if (!vop) in vop_bind()
2164 return -ENOMEM; in vop_bind()
2166 vop->dev = dev; in vop_bind()
2167 vop->data = vop_data; in vop_bind()
2168 vop->drm_dev = drm_dev; in vop_bind()
2169 dev_set_drvdata(dev, vop); in vop_bind()
2171 vop_win_init(vop); in vop_bind()
2174 vop->regs = devm_ioremap_resource(dev, res); in vop_bind()
2175 if (IS_ERR(vop->regs)) in vop_bind()
2176 return PTR_ERR(vop->regs); in vop_bind()
2177 vop->len = resource_size(res); in vop_bind()
2181 if (vop_data->lut_size != 1024 && vop_data->lut_size != 256) { in vop_bind()
2182 DRM_DEV_ERROR(dev, "unsupported gamma LUT size %d\n", vop_data->lut_size); in vop_bind()
2183 return -EINVAL; in vop_bind()
2185 vop->lut_regs = devm_ioremap_resource(dev, res); in vop_bind()
2186 if (IS_ERR(vop->lut_regs)) in vop_bind()
2187 return PTR_ERR(vop->lut_regs); in vop_bind()
2190 vop->regsbak = devm_kzalloc(dev, vop->len, GFP_KERNEL); in vop_bind()
2191 if (!vop->regsbak) in vop_bind()
2192 return -ENOMEM; in vop_bind()
2196 DRM_DEV_ERROR(dev, "cannot find irq for vop\n"); in vop_bind()
2199 vop->irq = (unsigned int)irq; in vop_bind()
2201 spin_lock_init(&vop->reg_lock); in vop_bind()
2202 spin_lock_init(&vop->irq_lock); in vop_bind()
2203 mutex_init(&vop->vop_lock); in vop_bind()
2205 ret = vop_create_crtc(vop); in vop_bind()
2209 pm_runtime_enable(&pdev->dev); in vop_bind()
2211 ret = vop_initial(vop); in vop_bind()
2213 DRM_DEV_ERROR(&pdev->dev, in vop_bind()
2214 "cannot initial vop dev - err %d\n", ret); in vop_bind()
2218 ret = devm_request_irq(dev, vop->irq, vop_isr, in vop_bind()
2219 IRQF_SHARED, dev_name(dev), vop); in vop_bind()
2223 if (vop->data->feature & VOP_FEATURE_INTERNAL_RGB) { in vop_bind()
2224 vop->rgb = rockchip_rgb_init(dev, &vop->crtc, vop->drm_dev); in vop_bind()
2225 if (IS_ERR(vop->rgb)) { in vop_bind()
2226 ret = PTR_ERR(vop->rgb); in vop_bind()
2236 pm_runtime_disable(&pdev->dev); in vop_bind()
2237 vop_destroy_crtc(vop); in vop_bind()
2243 struct vop *vop = dev_get_drvdata(dev); in vop_unbind() local
2245 if (vop->rgb) in vop_unbind()
2246 rockchip_rgb_fini(vop->rgb); in vop_unbind()
2249 vop_destroy_crtc(vop); in vop_unbind()
2251 clk_unprepare(vop->aclk); in vop_unbind()
2252 clk_unprepare(vop->hclk); in vop_unbind()
2253 clk_unprepare(vop->dclk); in vop_unbind()