summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDhaval Patel <pdhaval@quicinc.com>2016-11-11 12:11:24 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2016-11-11 12:11:24 -0800
commit113b255bab6f2030a40753203a268c882aa2cd48 (patch)
treeb4409c366da9015478a82b5167d49c64b52e5028 /drivers/gpu
parent3516a5609517fbbdd1451dd9c25062a5f82596e4 (diff)
parent023f3af0e93b058c2480e4cd56564be8b1a15019 (diff)
Merge "drm/msm/sde: add vblank reference counting to crtc" into dev/msm-4.4-drm_kms
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/msm/sde/sde_crtc.c59
-rw-r--r--drivers/gpu/drm/msm/sde/sde_crtc.h7
2 files changed, 65 insertions, 1 deletions
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 2ef5dc62c6c2..a610f4b8d2a3 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -365,6 +365,13 @@ static void _sde_crtc_complete_flip(struct drm_crtc *crtc,
static void sde_crtc_vblank_cb(void *data)
{
struct drm_crtc *crtc = (struct drm_crtc *)data;
+ struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
+
+ /* keep statistics on vblank callback - with auto reset via debugfs */
+ if (ktime_equal(sde_crtc->vblank_cb_time, ktime_set(0, 0)))
+ sde_crtc->vblank_cb_time = ktime_get();
+ else
+ sde_crtc->vblank_cb_count++;
drm_crtc_handle_vblank(crtc);
DRM_DEBUG_VBL("crtc%d\n", crtc->base.id);
@@ -759,6 +766,7 @@ static void sde_crtc_reset(struct drm_crtc *crtc)
static void sde_crtc_disable(struct drm_crtc *crtc)
{
struct sde_crtc *sde_crtc;
+ struct drm_encoder *encoder;
if (!crtc) {
SDE_ERROR("invalid crtc\n");
@@ -769,6 +777,19 @@ static void sde_crtc_disable(struct drm_crtc *crtc)
SDE_DEBUG("\n");
mutex_lock(&sde_crtc->crtc_lock);
+ if (atomic_read(&sde_crtc->vblank_refcount)) {
+ SDE_ERROR("crtc%d invalid vblank refcount %d\n",
+ crtc->base.id,
+ atomic_read(&sde_crtc->vblank_refcount));
+ drm_for_each_encoder(encoder, crtc->dev) {
+ if (encoder->crtc != crtc)
+ continue;
+ sde_encoder_register_vblank_callback(encoder, NULL,
+ NULL);
+ }
+ atomic_set(&sde_crtc->vblank_refcount, 0);
+ }
+
memset(sde_crtc->mixers, 0, sizeof(sde_crtc->mixers));
sde_crtc->num_mixers = 0;
mutex_unlock(&sde_crtc->crtc_lock);
@@ -947,10 +968,24 @@ end:
int sde_crtc_vblank(struct drm_crtc *crtc, bool en)
{
+ struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
struct drm_encoder *encoder;
struct drm_device *dev = crtc->dev;
- SDE_DEBUG("%d", en);
+ if (en && atomic_inc_return(&sde_crtc->vblank_refcount) == 1) {
+ SDE_DEBUG("crtc%d vblank enable\n", crtc->base.id);
+ } else if (!en && atomic_read(&sde_crtc->vblank_refcount) < 1) {
+ SDE_ERROR("crtc%d invalid vblank disable\n", crtc->base.id);
+ return -EINVAL;
+ } else if (!en && atomic_dec_return(&sde_crtc->vblank_refcount) == 0) {
+ SDE_DEBUG("crtc%d vblank disable\n", crtc->base.id);
+ } else {
+ SDE_DEBUG("crtc%d vblank %s refcount:%d\n",
+ crtc->base.id,
+ en ? "enable" : "disable",
+ atomic_read(&sde_crtc->vblank_refcount));
+ return 0;
+ }
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc != crtc)
@@ -1224,6 +1259,27 @@ static int _sde_debugfs_status_show(struct seq_file *s, void *data)
state->crtc_h);
seq_puts(s, "\n");
}
+
+ if (sde_crtc->vblank_cb_count) {
+ ktime_t diff = ktime_sub(ktime_get(), sde_crtc->vblank_cb_time);
+ s64 diff_ms = ktime_to_ms(diff);
+ s64 fps = diff_ms ? DIV_ROUND_CLOSEST(
+ sde_crtc->vblank_cb_count * 1000, diff_ms) : 0;
+
+ seq_printf(s,
+ "vblank fps:%lld count:%u total:%llums\n",
+ fps,
+ sde_crtc->vblank_cb_count,
+ ktime_to_ms(diff));
+
+ /* reset time & count for next measurement */
+ sde_crtc->vblank_cb_count = 0;
+ sde_crtc->vblank_cb_time = ktime_set(0, 0);
+ }
+
+ seq_printf(s, "vblank_refcount:%d\n",
+ atomic_read(&sde_crtc->vblank_refcount));
+
mutex_unlock(&sde_crtc->crtc_lock);
return 0;
@@ -1305,6 +1361,7 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane)
crtc = &sde_crtc->base;
crtc->dev = dev;
+ atomic_set(&sde_crtc->vblank_refcount, 0);
drm_crtc_init_with_planes(dev, crtc, plane, NULL, &sde_crtc_funcs);
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 4d1bb3c98329..c58bb097e8e6 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -54,6 +54,9 @@ struct sde_crtc_mixer {
* @property_defaults : Array of default values for generic property support
* @stage_cfg : H/w mixer stage configuration
* @debugfs_root : Parent of debugfs node
+ * @vblank_cb_count : count of vblank callback since last reset
+ * @vblank_cb_time : ktime at vblank count reset
+ * @vblank_refcount : reference count for vblank enable request
* @feature_list : list of color processing features supported on a crtc
* @active_list : list of color processing features are active
* @dirty_list : list of color processing features are dirty
@@ -81,6 +84,10 @@ struct sde_crtc {
struct sde_hw_stage_cfg stage_cfg;
struct dentry *debugfs_root;
+ u32 vblank_cb_count;
+ ktime_t vblank_cb_time;
+ atomic_t vblank_refcount;
+
struct list_head feature_list;
struct list_head active_list;
struct list_head dirty_list;