drm/msm: add timestamp param
authorRob Clark <robdclark@gmail.com>
Mon, 22 Feb 2016 11:26:21 +0000 (06:26 -0500)
committerRob Clark <robdclark@gmail.com>
Thu, 3 Mar 2016 16:55:32 +0000 (11:55 -0500)
We need this for GL_TIMESTAMP queries.

Note: currently only supported on a4xx.. a3xx doesn't have this
always-on counter.  I think we could emulate it with the one CP
counter that is available, but for now it is of limited usefulness
on a3xx (since we can't seem to do time-elapsed queries in any sane
way with the existing firmware on a3xx, and if you are trying to do
profiling on a tiler you want time-elapsed).  We can add that later
if it becomes useful.

Signed-off-by: Rob Clark <robdclark@gmail.com>
drivers/gpu/drm/msm/adreno/a4xx_gpu.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/adreno/adreno_gpu.h
include/uapi/drm/msm_drm.h

index 3d07a5a1f338baf923e987f86cff023100786034..b371f1c04a472e9afe09c5f0c652f18526272d63 100644 (file)
@@ -200,6 +200,11 @@ static int a4xx_hw_init(struct msm_gpu *gpu)
        /* Turn on performance counters: */
        gpu_write(gpu, REG_A4XX_RBBM_PERFCTR_CTL, 0x01);
 
+       /* use the first CP counter for timestamp queries.. userspace may set
+        * this as well but it selects the same counter/countable:
+        */
+       gpu_write(gpu, REG_A4XX_CP_PERFCTR_CP_SEL_0, CP_ALWAYS_COUNT);
+
        if (adreno_is_a430(adreno_gpu))
                gpu_write(gpu, REG_A4XX_UCHE_CACHE_WAYS_VFD, 0x07);
 
@@ -294,6 +299,7 @@ static int a4xx_hw_init(struct msm_gpu *gpu)
        gpu_write(gpu, REG_A4XX_CP_ME_CNTL, 0);
 
        a4xx_me_init(gpu);
+
        return 0;
 }
 
@@ -585,6 +591,22 @@ static int a4xx_pm_suspend(struct msm_gpu *gpu) {
        return 0;
 }
 
+static int a4xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
+{
+       uint32_t hi, lo, tmp;
+
+       tmp = gpu_read(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_HI);
+       do {
+               hi = tmp;
+               lo = gpu_read(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_LO);
+               tmp = gpu_read(gpu, REG_A4XX_RBBM_PERFCTR_CP_0_HI);
+       } while (tmp != hi);
+
+       *value = (((uint64_t)hi) << 32) | lo;
+
+       return 0;
+}
+
 static const struct adreno_gpu_funcs funcs = {
        .base = {
                .get_param = adreno_get_param,
@@ -602,6 +624,7 @@ static const struct adreno_gpu_funcs funcs = {
                .show = a4xx_show,
 #endif
        },
+       .get_timestamp = a4xx_get_timestamp,
 };
 
 struct msm_gpu *a4xx_gpu_init(struct drm_device *dev)
index 2859b19912592df6a192b3622ce2b15f11ba2371..4951172ede067f0beb9f9b863e77989c49bb84f3 100644 (file)
@@ -44,6 +44,10 @@ int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value)
        case MSM_PARAM_MAX_FREQ:
                *value = adreno_gpu->base.fast_rate;
                return 0;
+       case MSM_PARAM_TIMESTAMP:
+               if (adreno_gpu->funcs->get_timestamp)
+                       return adreno_gpu->funcs->get_timestamp(gpu, value);
+               return -EINVAL;
        default:
                DBG("%s: invalid param: %u", gpu->name, param);
                return -EINVAL;
index c26aea13df6d660295c14ace5f69a071c28304d5..1d07511f4d225eff989183bf01f2b8872c98ed4b 100644 (file)
@@ -114,6 +114,7 @@ struct adreno_rev {
 
 struct adreno_gpu_funcs {
        struct msm_gpu_funcs base;
+       int (*get_timestamp)(struct msm_gpu *gpu, uint64_t *value);
 };
 
 struct adreno_info {
index 0e3c4c48b326ff6a694e2d2fb197f1b4b22494f2..254d3e92d18e7d93177fbe0fcf218a87f95a07dc 100644 (file)
@@ -51,6 +51,7 @@ struct drm_msm_timespec {
 #define MSM_PARAM_GMEM_SIZE  0x02
 #define MSM_PARAM_CHIP_ID    0x03
 #define MSM_PARAM_MAX_FREQ   0x04
+#define MSM_PARAM_TIMESTAMP  0x05
 
 struct drm_msm_param {
        __u32 pipe;           /* in, MSM_PIPE_x */