linux/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
   3 */
   4
   5#define pr_fmt(fmt)     "[drm:%s:%d] " fmt, __func__, __LINE__
   6
   7#include <linux/debugfs.h>
   8#include <linux/errno.h>
   9#include <linux/mutex.h>
  10#include <linux/sort.h>
  11#include <linux/clk.h>
  12#include <linux/bitmap.h>
  13
  14#include "dpu_kms.h"
  15#include "dpu_trace.h"
  16#include "dpu_crtc.h"
  17#include "dpu_core_perf.h"
  18
  19/**
  20 * enum dpu_perf_mode - performance tuning mode
  21 * @DPU_PERF_MODE_NORMAL: performance controlled by user mode client
  22 * @DPU_PERF_MODE_MINIMUM: performance bounded by minimum setting
  23 * @DPU_PERF_MODE_FIXED: performance bounded by fixed setting
  24 */
  25enum dpu_perf_mode {
  26        DPU_PERF_MODE_NORMAL,
  27        DPU_PERF_MODE_MINIMUM,
  28        DPU_PERF_MODE_FIXED,
  29        DPU_PERF_MODE_MAX
  30};
  31
  32static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc)
  33{
  34        struct msm_drm_private *priv;
  35
  36        if (!crtc->dev || !crtc->dev->dev_private) {
  37                DPU_ERROR("invalid device\n");
  38                return NULL;
  39        }
  40
  41        priv = crtc->dev->dev_private;
  42        if (!priv || !priv->kms) {
  43                DPU_ERROR("invalid kms\n");
  44                return NULL;
  45        }
  46
  47        return to_dpu_kms(priv->kms);
  48}
  49
  50static bool _dpu_core_video_mode_intf_connected(struct drm_crtc *crtc)
  51{
  52        struct drm_crtc *tmp_crtc;
  53
  54        drm_for_each_crtc(tmp_crtc, crtc->dev) {
  55                if ((dpu_crtc_get_intf_mode(tmp_crtc) == INTF_MODE_VIDEO) &&
  56                                tmp_crtc->enabled) {
  57                        DPU_DEBUG("video interface connected crtc:%d\n",
  58                                tmp_crtc->base.id);
  59                        return true;
  60                }
  61        }
  62
  63        return false;
  64}
  65
  66static void _dpu_core_perf_calc_crtc(struct dpu_kms *kms,
  67                struct drm_crtc *crtc,
  68                struct drm_crtc_state *state,
  69                struct dpu_core_perf_params *perf)
  70{
  71        struct dpu_crtc_state *dpu_cstate;
  72
  73        if (!kms || !kms->catalog || !crtc || !state || !perf) {
  74                DPU_ERROR("invalid parameters\n");
  75                return;
  76        }
  77
  78        dpu_cstate = to_dpu_crtc_state(state);
  79        memset(perf, 0, sizeof(struct dpu_core_perf_params));
  80
  81        if (!dpu_cstate->bw_control) {
  82                perf->bw_ctl = kms->catalog->perf.max_bw_high *
  83                                        1000ULL;
  84                perf->max_per_pipe_ib = perf->bw_ctl;
  85                perf->core_clk_rate = kms->perf.max_core_clk_rate;
  86        } else if (kms->perf.perf_tune.mode == DPU_PERF_MODE_MINIMUM) {
  87                perf->bw_ctl = 0;
  88                perf->max_per_pipe_ib = 0;
  89                perf->core_clk_rate = 0;
  90        } else if (kms->perf.perf_tune.mode == DPU_PERF_MODE_FIXED) {
  91                perf->bw_ctl = kms->perf.fix_core_ab_vote;
  92                perf->max_per_pipe_ib = kms->perf.fix_core_ib_vote;
  93                perf->core_clk_rate = kms->perf.fix_core_clk_rate;
  94        }
  95
  96        DPU_DEBUG(
  97                "crtc=%d clk_rate=%llu core_ib=%llu core_ab=%llu\n",
  98                        crtc->base.id, perf->core_clk_rate,
  99                        perf->max_per_pipe_ib, perf->bw_ctl);
 100}
 101
 102int dpu_core_perf_crtc_check(struct drm_crtc *crtc,
 103                struct drm_crtc_state *state)
 104{
 105        u32 bw, threshold;
 106        u64 bw_sum_of_intfs = 0;
 107        enum dpu_crtc_client_type curr_client_type;
 108        bool is_video_mode;
 109        struct dpu_crtc_state *dpu_cstate;
 110        struct drm_crtc *tmp_crtc;
 111        struct dpu_kms *kms;
 112
 113        if (!crtc || !state) {
 114                DPU_ERROR("invalid crtc\n");
 115                return -EINVAL;
 116        }
 117
 118        kms = _dpu_crtc_get_kms(crtc);
 119        if (!kms || !kms->catalog) {
 120                DPU_ERROR("invalid parameters\n");
 121                return 0;
 122        }
 123
 124        /* we only need bandwidth check on real-time clients (interfaces) */
 125        if (dpu_crtc_get_client_type(crtc) == NRT_CLIENT)
 126                return 0;
 127
 128        dpu_cstate = to_dpu_crtc_state(state);
 129
 130        /* obtain new values */
 131        _dpu_core_perf_calc_crtc(kms, crtc, state, &dpu_cstate->new_perf);
 132
 133        bw_sum_of_intfs = dpu_cstate->new_perf.bw_ctl;
 134        curr_client_type = dpu_crtc_get_client_type(crtc);
 135
 136        drm_for_each_crtc(tmp_crtc, crtc->dev) {
 137                if (tmp_crtc->enabled &&
 138                    (dpu_crtc_get_client_type(tmp_crtc) ==
 139                                curr_client_type) && (tmp_crtc != crtc)) {
 140                        struct dpu_crtc_state *tmp_cstate =
 141                                to_dpu_crtc_state(tmp_crtc->state);
 142
 143                        DPU_DEBUG("crtc:%d bw:%llu ctrl:%d\n",
 144                                tmp_crtc->base.id, tmp_cstate->new_perf.bw_ctl,
 145                                tmp_cstate->bw_control);
 146                        /*
 147                         * For bw check only use the bw if the
 148                         * atomic property has been already set
 149                         */
 150                        if (tmp_cstate->bw_control)
 151                                bw_sum_of_intfs += tmp_cstate->new_perf.bw_ctl;
 152                }
 153
 154                /* convert bandwidth to kb */
 155                bw = DIV_ROUND_UP_ULL(bw_sum_of_intfs, 1000);
 156                DPU_DEBUG("calculated bandwidth=%uk\n", bw);
 157
 158                is_video_mode = dpu_crtc_get_intf_mode(crtc) == INTF_MODE_VIDEO;
 159                threshold = (is_video_mode ||
 160                        _dpu_core_video_mode_intf_connected(crtc)) ?
 161                        kms->catalog->perf.max_bw_low :
 162                        kms->catalog->perf.max_bw_high;
 163
 164                DPU_DEBUG("final threshold bw limit = %d\n", threshold);
 165
 166                if (!dpu_cstate->bw_control) {
 167                        DPU_DEBUG("bypass bandwidth check\n");
 168                } else if (!threshold) {
 169                        DPU_ERROR("no bandwidth limits specified\n");
 170                        return -E2BIG;
 171                } else if (bw > threshold) {
 172                        DPU_ERROR("exceeds bandwidth: %ukb > %ukb\n", bw,
 173                                        threshold);
 174                        return -E2BIG;
 175                }
 176        }
 177
 178        return 0;
 179}
 180
 181static int _dpu_core_perf_crtc_update_bus(struct dpu_kms *kms,
 182                struct drm_crtc *crtc)
 183{
 184        struct dpu_core_perf_params perf = { 0 };
 185        enum dpu_crtc_client_type curr_client_type
 186                                        = dpu_crtc_get_client_type(crtc);
 187        struct drm_crtc *tmp_crtc;
 188        struct dpu_crtc_state *dpu_cstate;
 189        int ret = 0;
 190
 191        drm_for_each_crtc(tmp_crtc, crtc->dev) {
 192                if (tmp_crtc->enabled &&
 193                        curr_client_type ==
 194                                dpu_crtc_get_client_type(tmp_crtc)) {
 195                        dpu_cstate = to_dpu_crtc_state(tmp_crtc->state);
 196
 197                        perf.max_per_pipe_ib = max(perf.max_per_pipe_ib,
 198                                        dpu_cstate->new_perf.max_per_pipe_ib);
 199
 200                        DPU_DEBUG("crtc=%d bw=%llu\n", tmp_crtc->base.id,
 201                                        dpu_cstate->new_perf.bw_ctl);
 202                }
 203        }
 204        return ret;
 205}
 206
 207/**
 208 * @dpu_core_perf_crtc_release_bw() - request zero bandwidth
 209 * @crtc - pointer to a crtc
 210 *
 211 * Function checks a state variable for the crtc, if all pending commit
 212 * requests are done, meaning no more bandwidth is needed, release
 213 * bandwidth request.
 214 */
 215void dpu_core_perf_crtc_release_bw(struct drm_crtc *crtc)
 216{
 217        struct drm_crtc *tmp_crtc;
 218        struct dpu_crtc *dpu_crtc;
 219        struct dpu_crtc_state *dpu_cstate;
 220        struct dpu_kms *kms;
 221
 222        if (!crtc) {
 223                DPU_ERROR("invalid crtc\n");
 224                return;
 225        }
 226
 227        kms = _dpu_crtc_get_kms(crtc);
 228        if (!kms || !kms->catalog) {
 229                DPU_ERROR("invalid kms\n");
 230                return;
 231        }
 232
 233        dpu_crtc = to_dpu_crtc(crtc);
 234        dpu_cstate = to_dpu_crtc_state(crtc->state);
 235
 236        /* only do this for command mode rt client */
 237        if (dpu_crtc_get_intf_mode(crtc) != INTF_MODE_CMD)
 238                return;
 239
 240        /*
 241         * If video interface present, cmd panel bandwidth cannot be
 242         * released.
 243         */
 244        if (dpu_crtc_get_intf_mode(crtc) == INTF_MODE_CMD)
 245                drm_for_each_crtc(tmp_crtc, crtc->dev) {
 246                        if (tmp_crtc->enabled &&
 247                                dpu_crtc_get_intf_mode(tmp_crtc) ==
 248                                                INTF_MODE_VIDEO)
 249                                return;
 250                }
 251
 252        /* Release the bandwidth */
 253        if (kms->perf.enable_bw_release) {
 254                trace_dpu_cmd_release_bw(crtc->base.id);
 255                DPU_DEBUG("Release BW crtc=%d\n", crtc->base.id);
 256                dpu_crtc->cur_perf.bw_ctl = 0;
 257                _dpu_core_perf_crtc_update_bus(kms, crtc);
 258        }
 259}
 260
 261static int _dpu_core_perf_set_core_clk_rate(struct dpu_kms *kms, u64 rate)
 262{
 263        struct dss_clk *core_clk = kms->perf.core_clk;
 264
 265        if (core_clk->max_rate && (rate > core_clk->max_rate))
 266                rate = core_clk->max_rate;
 267
 268        core_clk->rate = rate;
 269        return msm_dss_clk_set_rate(core_clk, 1);
 270}
 271
 272static u64 _dpu_core_perf_get_core_clk_rate(struct dpu_kms *kms)
 273{
 274        u64 clk_rate = kms->perf.perf_tune.min_core_clk;
 275        struct drm_crtc *crtc;
 276        struct dpu_crtc_state *dpu_cstate;
 277
 278        drm_for_each_crtc(crtc, kms->dev) {
 279                if (crtc->enabled) {
 280                        dpu_cstate = to_dpu_crtc_state(crtc->state);
 281                        clk_rate = max(dpu_cstate->new_perf.core_clk_rate,
 282                                                        clk_rate);
 283                        clk_rate = clk_round_rate(kms->perf.core_clk->clk,
 284                                        clk_rate);
 285                }
 286        }
 287
 288        if (kms->perf.perf_tune.mode == DPU_PERF_MODE_FIXED)
 289                clk_rate = kms->perf.fix_core_clk_rate;
 290
 291        DPU_DEBUG("clk:%llu\n", clk_rate);
 292
 293        return clk_rate;
 294}
 295
 296int dpu_core_perf_crtc_update(struct drm_crtc *crtc,
 297                int params_changed, bool stop_req)
 298{
 299        struct dpu_core_perf_params *new, *old;
 300        bool update_bus = false, update_clk = false;
 301        u64 clk_rate = 0;
 302        struct dpu_crtc *dpu_crtc;
 303        struct dpu_crtc_state *dpu_cstate;
 304        struct msm_drm_private *priv;
 305        struct dpu_kms *kms;
 306        int ret;
 307
 308        if (!crtc) {
 309                DPU_ERROR("invalid crtc\n");
 310                return -EINVAL;
 311        }
 312
 313        kms = _dpu_crtc_get_kms(crtc);
 314        if (!kms || !kms->catalog) {
 315                DPU_ERROR("invalid kms\n");
 316                return -EINVAL;
 317        }
 318        priv = kms->dev->dev_private;
 319
 320        dpu_crtc = to_dpu_crtc(crtc);
 321        dpu_cstate = to_dpu_crtc_state(crtc->state);
 322
 323        DPU_DEBUG("crtc:%d stop_req:%d core_clk:%llu\n",
 324                        crtc->base.id, stop_req, kms->perf.core_clk_rate);
 325
 326        old = &dpu_crtc->cur_perf;
 327        new = &dpu_cstate->new_perf;
 328
 329        if (crtc->enabled && !stop_req) {
 330                /*
 331                 * cases for bus bandwidth update.
 332                 * 1. new bandwidth vote - "ab or ib vote" is higher
 333                 *    than current vote for update request.
 334                 * 2. new bandwidth vote - "ab or ib vote" is lower
 335                 *    than current vote at end of commit or stop.
 336                 */
 337                if ((params_changed && ((new->bw_ctl > old->bw_ctl) ||
 338                        (new->max_per_pipe_ib > old->max_per_pipe_ib))) ||
 339                        (!params_changed && ((new->bw_ctl < old->bw_ctl) ||
 340                        (new->max_per_pipe_ib < old->max_per_pipe_ib)))) {
 341                        DPU_DEBUG("crtc=%d p=%d new_bw=%llu,old_bw=%llu\n",
 342                                crtc->base.id, params_changed,
 343                                new->bw_ctl, old->bw_ctl);
 344                        old->bw_ctl = new->bw_ctl;
 345                        old->max_per_pipe_ib = new->max_per_pipe_ib;
 346                        update_bus = true;
 347                }
 348
 349                if ((params_changed &&
 350                        (new->core_clk_rate > old->core_clk_rate)) ||
 351                        (!params_changed &&
 352                        (new->core_clk_rate < old->core_clk_rate))) {
 353                        old->core_clk_rate = new->core_clk_rate;
 354                        update_clk = true;
 355                }
 356        } else {
 357                DPU_DEBUG("crtc=%d disable\n", crtc->base.id);
 358                memset(old, 0, sizeof(*old));
 359                memset(new, 0, sizeof(*new));
 360                update_bus = true;
 361                update_clk = true;
 362        }
 363
 364        trace_dpu_perf_crtc_update(crtc->base.id, new->bw_ctl,
 365                new->core_clk_rate, stop_req, update_bus, update_clk);
 366
 367        if (update_bus) {
 368                ret = _dpu_core_perf_crtc_update_bus(kms, crtc);
 369                if (ret) {
 370                        DPU_ERROR("crtc-%d: failed to update bus bw vote\n",
 371                                  crtc->base.id);
 372                        return ret;
 373                }
 374        }
 375
 376        /*
 377         * Update the clock after bandwidth vote to ensure
 378         * bandwidth is available before clock rate is increased.
 379         */
 380        if (update_clk) {
 381                clk_rate = _dpu_core_perf_get_core_clk_rate(kms);
 382
 383                trace_dpu_core_perf_update_clk(kms->dev, stop_req, clk_rate);
 384
 385                ret = _dpu_core_perf_set_core_clk_rate(kms, clk_rate);
 386                if (ret) {
 387                        DPU_ERROR("failed to set %s clock rate %llu\n",
 388                                        kms->perf.core_clk->clk_name, clk_rate);
 389                        return ret;
 390                }
 391
 392                kms->perf.core_clk_rate = clk_rate;
 393                DPU_DEBUG("update clk rate = %lld HZ\n", clk_rate);
 394        }
 395        return 0;
 396}
 397
 398#ifdef CONFIG_DEBUG_FS
 399
 400static ssize_t _dpu_core_perf_mode_write(struct file *file,
 401                    const char __user *user_buf, size_t count, loff_t *ppos)
 402{
 403        struct dpu_core_perf *perf = file->private_data;
 404        struct dpu_perf_cfg *cfg = &perf->catalog->perf;
 405        u32 perf_mode = 0;
 406        int ret;
 407
 408        ret = kstrtouint_from_user(user_buf, count, 0, &perf_mode);
 409        if (ret)
 410                return ret;
 411
 412        if (perf_mode >= DPU_PERF_MODE_MAX)
 413                return -EINVAL;
 414
 415        if (perf_mode == DPU_PERF_MODE_FIXED) {
 416                DRM_INFO("fix performance mode\n");
 417        } else if (perf_mode == DPU_PERF_MODE_MINIMUM) {
 418                /* run the driver with max clk and BW vote */
 419                perf->perf_tune.min_core_clk = perf->max_core_clk_rate;
 420                perf->perf_tune.min_bus_vote =
 421                                (u64) cfg->max_bw_high * 1000;
 422                DRM_INFO("minimum performance mode\n");
 423        } else if (perf_mode == DPU_PERF_MODE_NORMAL) {
 424                /* reset the perf tune params to 0 */
 425                perf->perf_tune.min_core_clk = 0;
 426                perf->perf_tune.min_bus_vote = 0;
 427                DRM_INFO("normal performance mode\n");
 428        }
 429        perf->perf_tune.mode = perf_mode;
 430
 431        return count;
 432}
 433
 434static ssize_t _dpu_core_perf_mode_read(struct file *file,
 435                        char __user *buff, size_t count, loff_t *ppos)
 436{
 437        struct dpu_core_perf *perf = file->private_data;
 438        int len;
 439        char buf[128];
 440
 441        len = scnprintf(buf, sizeof(buf),
 442                        "mode %d min_mdp_clk %llu min_bus_vote %llu\n",
 443                        perf->perf_tune.mode,
 444                        perf->perf_tune.min_core_clk,
 445                        perf->perf_tune.min_bus_vote);
 446
 447        return simple_read_from_buffer(buff, count, ppos, buf, len);
 448}
 449
 450static const struct file_operations dpu_core_perf_mode_fops = {
 451        .open = simple_open,
 452        .read = _dpu_core_perf_mode_read,
 453        .write = _dpu_core_perf_mode_write,
 454};
 455
 456int dpu_core_perf_debugfs_init(struct dpu_kms *dpu_kms, struct dentry *parent)
 457{
 458        struct dpu_core_perf *perf = &dpu_kms->perf;
 459        struct dpu_mdss_cfg *catalog = perf->catalog;
 460        struct dentry *entry;
 461
 462        entry = debugfs_create_dir("core_perf", parent);
 463
 464        debugfs_create_u64("max_core_clk_rate", 0600, entry,
 465                        &perf->max_core_clk_rate);
 466        debugfs_create_u64("core_clk_rate", 0600, entry,
 467                        &perf->core_clk_rate);
 468        debugfs_create_u32("enable_bw_release", 0600, entry,
 469                        (u32 *)&perf->enable_bw_release);
 470        debugfs_create_u32("threshold_low", 0600, entry,
 471                        (u32 *)&catalog->perf.max_bw_low);
 472        debugfs_create_u32("threshold_high", 0600, entry,
 473                        (u32 *)&catalog->perf.max_bw_high);
 474        debugfs_create_u32("min_core_ib", 0600, entry,
 475                        (u32 *)&catalog->perf.min_core_ib);
 476        debugfs_create_u32("min_llcc_ib", 0600, entry,
 477                        (u32 *)&catalog->perf.min_llcc_ib);
 478        debugfs_create_u32("min_dram_ib", 0600, entry,
 479                        (u32 *)&catalog->perf.min_dram_ib);
 480        debugfs_create_file("perf_mode", 0600, entry,
 481                        (u32 *)perf, &dpu_core_perf_mode_fops);
 482        debugfs_create_u64("fix_core_clk_rate", 0600, entry,
 483                        &perf->fix_core_clk_rate);
 484        debugfs_create_u64("fix_core_ib_vote", 0600, entry,
 485                        &perf->fix_core_ib_vote);
 486        debugfs_create_u64("fix_core_ab_vote", 0600, entry,
 487                        &perf->fix_core_ab_vote);
 488
 489        return 0;
 490}
 491#endif
 492
 493void dpu_core_perf_destroy(struct dpu_core_perf *perf)
 494{
 495        if (!perf) {
 496                DPU_ERROR("invalid parameters\n");
 497                return;
 498        }
 499
 500        perf->max_core_clk_rate = 0;
 501        perf->core_clk = NULL;
 502        perf->catalog = NULL;
 503        perf->dev = NULL;
 504}
 505
 506int dpu_core_perf_init(struct dpu_core_perf *perf,
 507                struct drm_device *dev,
 508                struct dpu_mdss_cfg *catalog,
 509                struct dss_clk *core_clk)
 510{
 511        perf->dev = dev;
 512        perf->catalog = catalog;
 513        perf->core_clk = core_clk;
 514
 515        perf->max_core_clk_rate = core_clk->max_rate;
 516        if (!perf->max_core_clk_rate) {
 517                DPU_DEBUG("optional max core clk rate, use default\n");
 518                perf->max_core_clk_rate = DPU_PERF_DEFAULT_MAX_CORE_CLK_RATE;
 519        }
 520
 521        return 0;
 522}
 523