disp: msm: sde: move resource state change to display thread

In the current kernel version calling kthread_mod_delayed_work
in irq context is not allowed. Due to this resource control state
change to idle on frame done is handled in display thread context.

Change-Id: I709f7e04ac23d7dde72cea1c19d3767b6abc147e
Signed-off-by: Abhijit Kulkarni <kabhijit@codeaurora.org>
This commit is contained in:
Abhijit Kulkarni
2020-02-05 18:38:08 -08:00
parent 06ca9dd1e5
commit 2c6c071e45

View File

@@ -84,12 +84,9 @@
* Event that signals the start of the transfer. When this event is * Event that signals the start of the transfer. When this event is
* received, enable MDP/DSI core clocks and request RSC with CMD state. * received, enable MDP/DSI core clocks and request RSC with CMD state.
* Regardless of the previous state, the resource should be in ON state * Regardless of the previous state, the resource should be in ON state
* at the end of this event. * at the end of this event. At the end of this event, a delayed work is
* @SDE_ENC_RC_EVENT_FRAME_DONE: * scheduled to go to IDLE_PC state after IDLE_POWERCOLLAPSE_DURATION
* This event happens at INTERRUPT level. * ktime.
* Event signals the end of the data transfer after the PP FRAME_DONE
* event. At the end of this event, a delayed work is scheduled to go to
* IDLE_PC state after IDLE_POWERCOLLAPSE_DURATION time.
* @SDE_ENC_RC_EVENT_PRE_STOP: * @SDE_ENC_RC_EVENT_PRE_STOP:
* This event happens at NORMAL priority. * This event happens at NORMAL priority.
* This event, when received during the ON state, set RSC to IDLE, and * This event, when received during the ON state, set RSC to IDLE, and
@@ -128,7 +125,6 @@
*/ */
enum sde_enc_rc_events { enum sde_enc_rc_events {
SDE_ENC_RC_EVENT_KICKOFF = 1, SDE_ENC_RC_EVENT_KICKOFF = 1,
SDE_ENC_RC_EVENT_FRAME_DONE,
SDE_ENC_RC_EVENT_PRE_STOP, SDE_ENC_RC_EVENT_PRE_STOP,
SDE_ENC_RC_EVENT_STOP, SDE_ENC_RC_EVENT_STOP,
SDE_ENC_RC_EVENT_PRE_MODESET, SDE_ENC_RC_EVENT_PRE_MODESET,
@@ -1491,6 +1487,45 @@ void sde_encoder_control_idle_pc(struct drm_encoder *drm_enc, bool enable)
SDE_EVT32(sde_enc->idle_pc_enabled); SDE_EVT32(sde_enc->idle_pc_enabled);
} }
static void _sde_encoder_rc_restart_delayed(struct sde_encoder_virt *sde_enc,
u32 sw_event)
{
struct drm_encoder *drm_enc = &sde_enc->base;
struct msm_drm_private *priv;
unsigned int lp, idle_pc_duration;
struct msm_drm_thread *disp_thread;
bool autorefresh_enabled = false;
autorefresh_enabled = _sde_encoder_is_autorefresh_enabled(sde_enc);
if (autorefresh_enabled)
return;
/* set idle timeout based on master connector's lp value */
if (sde_enc->cur_master)
lp = sde_connector_get_lp(
sde_enc->cur_master->connector);
else
lp = SDE_MODE_DPMS_ON;
if (lp == SDE_MODE_DPMS_LP2)
idle_pc_duration = IDLE_SHORT_TIMEOUT;
else
idle_pc_duration = IDLE_POWERCOLLAPSE_DURATION;
priv = drm_enc->dev->dev_private;
disp_thread = &priv->disp_thread[sde_enc->crtc->index];
kthread_mod_delayed_work(
&disp_thread->worker,
&sde_enc->delayed_off_work,
msecs_to_jiffies(idle_pc_duration));
SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
autorefresh_enabled,
idle_pc_duration, SDE_EVTLOG_FUNC_CASE2);
SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work scheduled\n",
sw_event);
}
static void _sde_encoder_rc_cancel_delayed(struct sde_encoder_virt *sde_enc, static void _sde_encoder_rc_cancel_delayed(struct sde_encoder_virt *sde_enc,
u32 sw_event) u32 sw_event)
{ {
@@ -1505,9 +1540,6 @@ static int _sde_encoder_rc_kickoff(struct drm_encoder *drm_enc,
{ {
int ret = 0; int ret = 0;
/* cancel delayed off work, if any */
_sde_encoder_rc_cancel_delayed(sde_enc, sw_event);
mutex_lock(&sde_enc->rc_lock); mutex_lock(&sde_enc->rc_lock);
/* return if the resource control is already in ON state */ /* return if the resource control is already in ON state */
@@ -1547,88 +1579,13 @@ static int _sde_encoder_rc_kickoff(struct drm_encoder *drm_enc,
SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE1); SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE1);
sde_enc->rc_state = SDE_ENC_RC_STATE_ON; sde_enc->rc_state = SDE_ENC_RC_STATE_ON;
/* restart delayed off work, if required */
_sde_encoder_rc_restart_delayed(sde_enc, sw_event);
end: end:
mutex_unlock(&sde_enc->rc_lock); mutex_unlock(&sde_enc->rc_lock);
return ret; return ret;
} }
static int _sde_encoder_rc_frame_done(struct drm_encoder *drm_enc,
u32 sw_event, struct sde_encoder_virt *sde_enc,
struct msm_drm_private *priv)
{
unsigned int lp, idle_pc_duration;
struct msm_drm_thread *disp_thread;
bool autorefresh_enabled = false;
if (!sde_enc->crtc) {
SDE_ERROR("invalid crtc, sw_event:%u\n", sw_event);
return -EINVAL;
}
if (sde_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) {
SDE_ERROR("invalid crtc index :%u\n",
sde_enc->crtc->index);
return -EINVAL;
}
disp_thread = &priv->disp_thread[sde_enc->crtc->index];
/*
* mutex lock is not used as this event happens at interrupt
* context. And locking is not required as, the other events
* like KICKOFF and STOP does a wait-for-idle before executing
* the resource_control
*/
if (sde_enc->rc_state != SDE_ENC_RC_STATE_ON) {
SDE_ERROR_ENC(sde_enc, "sw_event:%d,rc:%d-unexpected\n",
sw_event, sde_enc->rc_state);
SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
SDE_EVTLOG_ERROR);
return -EINVAL;
}
/*
* schedule off work item only when there are no
* frames pending
*/
if (sde_crtc_frame_pending(sde_enc->crtc) > 1) {
SDE_DEBUG_ENC(sde_enc, "skip schedule work");
SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
SDE_EVTLOG_FUNC_CASE2);
return 0;
}
/* schedule delayed off work if autorefresh is disabled */
if (sde_enc->cur_master &&
sde_enc->cur_master->ops.is_autorefresh_enabled)
autorefresh_enabled =
sde_enc->cur_master->ops.is_autorefresh_enabled(
sde_enc->cur_master);
/* set idle timeout based on master connector's lp value */
if (sde_enc->cur_master)
lp = sde_connector_get_lp(
sde_enc->cur_master->connector);
else
lp = SDE_MODE_DPMS_ON;
if (lp == SDE_MODE_DPMS_LP2)
idle_pc_duration = IDLE_SHORT_TIMEOUT;
else
idle_pc_duration = IDLE_POWERCOLLAPSE_DURATION;
if (!autorefresh_enabled)
kthread_mod_delayed_work(
&disp_thread->worker,
&sde_enc->delayed_off_work,
msecs_to_jiffies(idle_pc_duration));
SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
autorefresh_enabled,
idle_pc_duration, SDE_EVTLOG_FUNC_CASE2);
SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work scheduled\n",
sw_event);
return 0;
}
static int _sde_encoder_rc_pre_stop(struct drm_encoder *drm_enc, static int _sde_encoder_rc_pre_stop(struct drm_encoder *drm_enc,
u32 sw_event, struct sde_encoder_virt *sde_enc, bool is_vid_mode) u32 sw_event, struct sde_encoder_virt *sde_enc, bool is_vid_mode)
{ {
@@ -1828,6 +1785,8 @@ static int _sde_encoder_rc_idle(struct drm_encoder *drm_enc,
SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
sde_crtc_frame_pending(sde_enc->crtc), sde_crtc_frame_pending(sde_enc->crtc),
SDE_EVTLOG_ERROR); SDE_EVTLOG_ERROR);
_sde_encoder_rc_restart_delayed(sde_enc,
SDE_ENC_RC_EVENT_ENTER_IDLE);
goto end; goto end;
} }
@@ -1965,10 +1924,6 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
ret = _sde_encoder_rc_kickoff(drm_enc, sw_event, sde_enc, ret = _sde_encoder_rc_kickoff(drm_enc, sw_event, sde_enc,
is_vid_mode); is_vid_mode);
break; break;
case SDE_ENC_RC_EVENT_FRAME_DONE:
ret = _sde_encoder_rc_frame_done(drm_enc, sw_event, sde_enc,
priv);
break;
case SDE_ENC_RC_EVENT_PRE_STOP: case SDE_ENC_RC_EVENT_PRE_STOP:
ret = _sde_encoder_rc_pre_stop(drm_enc, sw_event, sde_enc, ret = _sde_encoder_rc_pre_stop(drm_enc, sw_event, sde_enc,
is_vid_mode); is_vid_mode);
@@ -2965,9 +2920,6 @@ static void sde_encoder_frame_done_callback(
} }
if (trigger) { if (trigger) {
sde_encoder_resource_control(drm_enc,
SDE_ENC_RC_EVENT_FRAME_DONE);
if (sde_enc->crtc_frame_event_cb) if (sde_enc->crtc_frame_event_cb)
sde_enc->crtc_frame_event_cb( sde_enc->crtc_frame_event_cb(
&sde_enc->crtc_frame_event_cb_data, &sde_enc->crtc_frame_event_cb_data,
@@ -2976,10 +2928,6 @@ static void sde_encoder_frame_done_callback(
atomic_set(&sde_enc->frame_done_cnt[i], 0); atomic_set(&sde_enc->frame_done_cnt[i], 0);
} }
} else if (sde_enc->crtc_frame_event_cb) { } else if (sde_enc->crtc_frame_event_cb) {
if (!is_cmd_mode)
sde_encoder_resource_control(drm_enc,
SDE_ENC_RC_EVENT_FRAME_DONE);
sde_enc->crtc_frame_event_cb( sde_enc->crtc_frame_event_cb(
&sde_enc->crtc_frame_event_cb_data, event); &sde_enc->crtc_frame_event_cb_data, event);
} }