summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c')
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c130
1 files changed, 55 insertions, 75 deletions
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index b3417d56032d..bf513411b243 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -9,11 +9,13 @@
#include <linux/sort.h>
#include <linux/debugfs.h>
#include <linux/ktime.h>
+
#include <drm/drm_crtc.h>
#include <drm/drm_flip_work.h>
#include <drm/drm_mode.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_rect.h>
+#include <drm/drm_vblank.h>
#include "dpu_kms.h"
#include "dpu_hw_lm.h"
@@ -195,10 +197,6 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc)
DPU_DEBUG("%s\n", dpu_crtc->name);
for (i = 0; i < cstate->num_mixers; i++) {
- if (!mixer[i].hw_lm || !mixer[i].lm_ctl) {
- DPU_ERROR("invalid lm or ctl assigned to mixer\n");
- return;
- }
mixer[i].mixer_op_mode = 0;
mixer[i].flush_mask = 0;
if (mixer[i].lm_ctl->ops.clear_all_blendstages)
@@ -264,11 +262,20 @@ enum dpu_intf_mode dpu_crtc_get_intf_mode(struct drm_crtc *crtc)
{
struct drm_encoder *encoder;
- if (!crtc || !crtc->dev) {
+ if (!crtc) {
DPU_ERROR("invalid crtc\n");
return INTF_MODE_NONE;
}
+ /*
+ * TODO: This function is called from dpu debugfs and as part of atomic
+ * check. When called from debugfs, the crtc->mutex must be held to
+ * read crtc->state. However reading crtc->state from atomic check isn't
+ * allowed (unless you have a good reason, a big comment, and a deep
+ * understanding of how the atomic/modeset locks work (<- and this is
+ * probably not possible)). So we'll keep the WARN_ON here for now, but
+ * really we need to figure out a better way to track our operating mode
+ */
WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
/* TODO: Returns the first INTF_MODE, could there be multiple values? */
@@ -292,19 +299,6 @@ void dpu_crtc_vblank_callback(struct drm_crtc *crtc)
trace_dpu_crtc_vblank_cb(DRMID(crtc));
}
-static void dpu_crtc_release_bw_unlocked(struct drm_crtc *crtc)
-{
- int ret = 0;
- struct drm_modeset_acquire_ctx ctx;
-
- DRM_MODESET_LOCK_ALL_BEGIN(crtc->dev, ctx, 0, ret);
- dpu_core_perf_crtc_release_bw(crtc);
- DRM_MODESET_LOCK_ALL_END(ctx, ret);
- if (ret)
- DRM_ERROR("Failed to acquire modeset locks to release bw, %d\n",
- ret);
-}
-
static void dpu_crtc_frame_event_work(struct kthread_work *work)
{
struct dpu_crtc_frame_event *fevent = container_of(work,
@@ -324,17 +318,12 @@ static void dpu_crtc_frame_event_work(struct kthread_work *work)
| DPU_ENCODER_FRAME_EVENT_PANEL_DEAD)) {
if (atomic_read(&dpu_crtc->frame_pending) < 1) {
- /* this should not happen */
- DRM_ERROR("crtc%d ev:%u ts:%lld frame_pending:%d\n",
- crtc->base.id,
- fevent->event,
- ktime_to_ns(fevent->ts),
- atomic_read(&dpu_crtc->frame_pending));
+ /* ignore vblank when not pending */
} else if (atomic_dec_return(&dpu_crtc->frame_pending) == 0) {
/* release bandwidth and other resources */
trace_dpu_crtc_frame_event_done(DRMID(crtc),
fevent->event);
- dpu_crtc_release_bw_unlocked(crtc);
+ dpu_core_perf_crtc_release_bw(crtc);
} else {
trace_dpu_crtc_frame_event_more_pending(DRMID(crtc),
fevent->event);
@@ -407,13 +396,8 @@ static void dpu_crtc_frame_event_cb(void *data, u32 event)
kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work);
}
-void dpu_crtc_complete_commit(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state)
+void dpu_crtc_complete_commit(struct drm_crtc *crtc)
{
- if (!crtc || !crtc->state) {
- DPU_ERROR("invalid crtc\n");
- return;
- }
trace_dpu_crtc_complete_commit(DRMID(crtc));
}
@@ -623,13 +607,12 @@ static int _dpu_crtc_wait_for_frame_done(struct drm_crtc *crtc)
return rc;
}
-void dpu_crtc_commit_kickoff(struct drm_crtc *crtc, bool async)
+void dpu_crtc_commit_kickoff(struct drm_crtc *crtc)
{
struct drm_encoder *encoder;
struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc);
struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state);
- int ret;
/*
* If no mixers has been allocated in dpu_crtc_atomic_check(),
@@ -647,37 +630,22 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc, bool async)
*/
drm_for_each_encoder_mask(encoder, crtc->dev,
crtc->state->encoder_mask)
- dpu_encoder_prepare_for_kickoff(encoder, async);
-
- if (!async) {
- /* wait for frame_event_done completion */
- DPU_ATRACE_BEGIN("wait_for_frame_done_event");
- ret = _dpu_crtc_wait_for_frame_done(crtc);
- DPU_ATRACE_END("wait_for_frame_done_event");
- if (ret) {
- DPU_ERROR("crtc%d wait for frame done failed;frame_pending%d\n",
- crtc->base.id,
- atomic_read(&dpu_crtc->frame_pending));
- goto end;
- }
+ dpu_encoder_prepare_for_kickoff(encoder);
- if (atomic_inc_return(&dpu_crtc->frame_pending) == 1) {
- /* acquire bandwidth and other resources */
- DPU_DEBUG("crtc%d first commit\n", crtc->base.id);
- } else
- DPU_DEBUG("crtc%d commit\n", crtc->base.id);
+ if (atomic_inc_return(&dpu_crtc->frame_pending) == 1) {
+ /* acquire bandwidth and other resources */
+ DPU_DEBUG("crtc%d first commit\n", crtc->base.id);
+ } else
+ DPU_DEBUG("crtc%d commit\n", crtc->base.id);
- dpu_crtc->play_count++;
- }
+ dpu_crtc->play_count++;
dpu_vbif_clear_errors(dpu_kms);
drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask)
- dpu_encoder_kickoff(encoder, async);
+ dpu_encoder_kickoff(encoder);
-end:
- if (!async)
- reinit_completion(&dpu_crtc->frame_done_comp);
+ reinit_completion(&dpu_crtc->frame_done_comp);
DPU_ATRACE_END("crtc_commit");
}
@@ -729,8 +697,9 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
struct drm_encoder *encoder;
struct msm_drm_private *priv;
unsigned long flags;
+ bool release_bandwidth = false;
- if (!crtc || !crtc->dev || !crtc->dev->dev_private || !crtc->state) {
+ if (!crtc || !crtc->state) {
DPU_ERROR("invalid crtc\n");
return;
}
@@ -745,8 +714,15 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
drm_crtc_vblank_off(crtc);
drm_for_each_encoder_mask(encoder, crtc->dev,
- old_crtc_state->encoder_mask)
+ old_crtc_state->encoder_mask) {
+ /* in video mode, we hold an extra bandwidth reference
+ * as we cannot drop bandwidth at frame-done if any
+ * crtc is being used in video mode.
+ */
+ if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO)
+ release_bandwidth = true;
dpu_encoder_assign_crtc(encoder, NULL);
+ }
/* wait for frame_event_done completion */
if (_dpu_crtc_wait_for_frame_done(crtc))
@@ -760,7 +736,8 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
if (atomic_read(&dpu_crtc->frame_pending)) {
trace_dpu_crtc_disable_frame_pending(DRMID(crtc),
atomic_read(&dpu_crtc->frame_pending));
- dpu_core_perf_crtc_release_bw(crtc);
+ if (release_bandwidth)
+ dpu_core_perf_crtc_release_bw(crtc);
atomic_set(&dpu_crtc->frame_pending, 0);
}
@@ -792,8 +769,9 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
struct dpu_crtc *dpu_crtc;
struct drm_encoder *encoder;
struct msm_drm_private *priv;
+ bool request_bandwidth;
- if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
+ if (!crtc) {
DPU_ERROR("invalid crtc\n");
return;
}
@@ -804,9 +782,19 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
dpu_crtc = to_dpu_crtc(crtc);
- drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask)
+ drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) {
+ /* in video mode, we hold an extra bandwidth reference
+ * as we cannot drop bandwidth at frame-done if any
+ * crtc is being used in video mode.
+ */
+ if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO)
+ request_bandwidth = true;
dpu_encoder_register_frame_event_callback(encoder,
dpu_crtc_frame_event_cb, (void *)crtc);
+ }
+
+ if (request_bandwidth)
+ atomic_inc(&_dpu_crtc_get_kms(crtc)->bandwidth_ref);
trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc);
dpu_crtc->enabled = true;
@@ -981,6 +969,8 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
}
}
+ atomic_inc(&_dpu_crtc_get_kms(crtc)->bandwidth_ref);
+
rc = dpu_core_perf_crtc_check(crtc, state);
if (rc) {
DPU_ERROR("crtc%d failed performance check %d\n",
@@ -1119,14 +1109,9 @@ static int _dpu_debugfs_status_show(struct seq_file *s, void *data)
for (i = 0; i < cstate->num_mixers; ++i) {
m = &cstate->mixers[i];
- if (!m->hw_lm)
- seq_printf(s, "\tmixer[%d] has no lm\n", i);
- else if (!m->lm_ctl)
- seq_printf(s, "\tmixer[%d] has no ctl\n", i);
- else
- seq_printf(s, "\tmixer:%d ctl:%d width:%d height:%d\n",
- m->hw_lm->idx - LM_0, m->lm_ctl->idx - CTL_0,
- out_width, mode->vdisplay);
+ seq_printf(s, "\tmixer:%d ctl:%d width:%d height:%d\n",
+ m->hw_lm->idx - LM_0, m->lm_ctl->idx - CTL_0,
+ out_width, mode->vdisplay);
}
seq_puts(s, "\n");
@@ -1303,13 +1288,8 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane,
{
struct drm_crtc *crtc = NULL;
struct dpu_crtc *dpu_crtc = NULL;
- struct msm_drm_private *priv = NULL;
- struct dpu_kms *kms = NULL;
int i;
- priv = dev->dev_private;
- kms = to_dpu_kms(priv->kms);
-
dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL);
if (!dpu_crtc)
return ERR_PTR(-ENOMEM);
OpenPOWER on IntegriCloud