mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 11:26:02 +09:00
drm/rockchip: vop2: add vop2_crtc_wait_vact_end for psr panel
Signed-off-by: Sandy Huang <hjc@rock-chips.com> Signed-off-by: Wyon Bi <bivvy.bi@rock-chips.com> Change-Id: I29a0b89fa9b2e5f3dd50d699582b3d060f7b3363
This commit is contained in:
@@ -13,6 +13,8 @@
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_plane_helper.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_self_refresh_helper.h>
|
||||
|
||||
#include <drm/drm_writeback.h>
|
||||
#ifdef CONFIG_DRM_ANALOGIX_DP
|
||||
#include <drm/bridge/analogix_dp.h>
|
||||
@@ -680,6 +682,9 @@ struct vop2 {
|
||||
|
||||
bool loader_protect;
|
||||
|
||||
bool aclk_rate_reset;
|
||||
unsigned long aclk_rate;
|
||||
|
||||
const struct vop2_data *data;
|
||||
/* Number of win that registered as plane,
|
||||
* maybe less than the total number of hardware
|
||||
@@ -3591,6 +3596,19 @@ static int vop2_clk_set_parent_extend(struct vop2_video_port *vp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vop2_crtc_atomic_disable_for_psr(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_state)
|
||||
{
|
||||
struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
||||
struct vop2 *vop2 = vp->vop2;
|
||||
|
||||
vop2_disable_all_planes_for_crtc(crtc);
|
||||
drm_crtc_vblank_off(crtc);
|
||||
vop2->aclk_rate = clk_get_rate(vop2->aclk);
|
||||
clk_set_rate(vop2->aclk, vop2->aclk_rate / 3);
|
||||
vop2->aclk_rate_reset = true;
|
||||
}
|
||||
|
||||
static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_state)
|
||||
{
|
||||
@@ -3603,6 +3621,12 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
int ret;
|
||||
|
||||
WARN_ON(vp->event);
|
||||
|
||||
if (crtc->state->self_refresh_active) {
|
||||
vop2_crtc_atomic_disable_for_psr(crtc, old_state);
|
||||
goto out;
|
||||
}
|
||||
|
||||
vop2_lock(vop2);
|
||||
DRM_DEV_INFO(vop2->dev, "Crtc atomic disable vp%d\n", vp->id);
|
||||
drm_crtc_vblank_off(crtc);
|
||||
@@ -3686,6 +3710,7 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
vop2->active_vp_mask &= ~BIT(vp->id);
|
||||
vop2_set_system_status(vop2);
|
||||
|
||||
out:
|
||||
if (crtc->state->event && !crtc->state->active) {
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
drm_crtc_send_vblank_event(crtc, crtc->state->event);
|
||||
@@ -4814,6 +4839,89 @@ static void vop2_crtc_cancel_pending_vblank(struct drm_crtc *crtc,
|
||||
spin_unlock_irqrestore(&drm->event_lock, flags);
|
||||
}
|
||||
|
||||
static bool vop2_crtc_line_flag_irq_is_enabled(struct vop2_video_port *vp)
|
||||
{
|
||||
struct vop2 *vop2 = vp->vop2;
|
||||
const struct vop2_data *vop2_data = vop2->data;
|
||||
const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
|
||||
const struct vop_intr *intr = vp_data->intr;
|
||||
uint32_t line_flag_irq;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&vop2->irq_lock, flags);
|
||||
line_flag_irq = VOP_INTR_GET_TYPE(vop2, intr, enable, LINE_FLAG_INTR);
|
||||
spin_unlock_irqrestore(&vop2->irq_lock, flags);
|
||||
|
||||
return !!line_flag_irq;
|
||||
}
|
||||
|
||||
static void vop2_crtc_line_flag_irq_enable(struct vop2_video_port *vp)
|
||||
{
|
||||
struct vop2 *vop2 = vp->vop2;
|
||||
const struct vop2_data *vop2_data = vop2->data;
|
||||
const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
|
||||
const struct vop_intr *intr = vp_data->intr;
|
||||
unsigned long flags;
|
||||
|
||||
if (!vop2->is_enabled)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&vop2->irq_lock, flags);
|
||||
VOP_INTR_SET_TYPE(vop2, intr, clear, LINE_FLAG_INTR, 1);
|
||||
VOP_INTR_SET_TYPE(vop2, intr, enable, LINE_FLAG_INTR, 1);
|
||||
spin_unlock_irqrestore(&vop2->irq_lock, flags);
|
||||
}
|
||||
|
||||
static void vop2_crtc_line_flag_irq_disable(struct vop2_video_port *vp)
|
||||
{
|
||||
struct vop2 *vop2 = vp->vop2;
|
||||
const struct vop2_data *vop2_data = vop2->data;
|
||||
const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
|
||||
const struct vop_intr *intr = vp_data->intr;
|
||||
unsigned long flags;
|
||||
|
||||
if (!vop2->is_enabled)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&vop2->irq_lock, flags);
|
||||
VOP_INTR_SET_TYPE(vop2, intr, enable, LINE_FLAG_INTR, 0);
|
||||
spin_unlock_irqrestore(&vop2->irq_lock, flags);
|
||||
}
|
||||
|
||||
static int vop2_crtc_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout)
|
||||
{
|
||||
struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
||||
struct vop2 *vop2 = vp->vop2;
|
||||
unsigned long jiffies_left;
|
||||
int ret = 0;
|
||||
|
||||
if (!vop2->is_enabled)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&vop2->vop2_lock);
|
||||
|
||||
if (vop2_crtc_line_flag_irq_is_enabled(vp)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
reinit_completion(&vp->line_flag_completion);
|
||||
vop2_crtc_line_flag_irq_enable(vp);
|
||||
jiffies_left = wait_for_completion_timeout(&vp->line_flag_completion,
|
||||
msecs_to_jiffies(mstimeout));
|
||||
vop2_crtc_line_flag_irq_disable(vp);
|
||||
|
||||
if (jiffies_left == 0) {
|
||||
DRM_DEV_ERROR(vop2->dev, "timeout waiting for lineflag IRQ\n");
|
||||
ret = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&vop2->vop2_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vop2_crtc_enable_line_flag_event(struct drm_crtc *crtc, uint32_t line)
|
||||
{
|
||||
struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
||||
@@ -5368,6 +5476,7 @@ static const struct rockchip_crtc_funcs private_crtc_funcs = {
|
||||
.bandwidth = vop2_crtc_bandwidth,
|
||||
.crtc_close = vop2_crtc_close,
|
||||
.te_handler = vop2_crtc_te_handler,
|
||||
.wait_vact_end = vop2_crtc_wait_vact_end,
|
||||
};
|
||||
|
||||
static bool vop2_crtc_mode_fixup(struct drm_crtc *crtc,
|
||||
@@ -6110,6 +6219,15 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state
|
||||
int port_mux;
|
||||
int ret;
|
||||
|
||||
if (old_state && old_state->self_refresh_active) {
|
||||
drm_crtc_vblank_on(crtc);
|
||||
if (vop2->aclk_rate_reset)
|
||||
clk_set_rate(vop2->aclk, vop2->aclk_rate);
|
||||
vop2->aclk_rate_reset = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
vop2->active_vp_mask |= BIT(vp->id);
|
||||
vop2_set_system_status(vop2);
|
||||
|
||||
@@ -8660,6 +8778,13 @@ static int vop2_create_crtc(struct vop2 *vop2)
|
||||
}
|
||||
vop2_crtc_create_plane_mask_property(vop2, crtc);
|
||||
vop2_crtc_create_feature_property(vop2, crtc);
|
||||
|
||||
ret = drm_self_refresh_helper_init(crtc);
|
||||
if (ret)
|
||||
DRM_DEV_DEBUG_KMS(vop2->dev,
|
||||
"Failed to init %s with SR helpers %d, ignoring\n",
|
||||
crtc->name, ret);
|
||||
|
||||
registered_num_crtcs++;
|
||||
}
|
||||
|
||||
@@ -8722,6 +8847,8 @@ static void vop2_destroy_crtc(struct drm_crtc *crtc)
|
||||
{
|
||||
struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
||||
|
||||
drm_self_refresh_helper_cleanup(crtc);
|
||||
|
||||
of_node_put(crtc->port);
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user