linux/drivers/gpu/drm/v3d/v3d_debugfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/* Copyright (C) 2014-2018 Broadcom */
   3
   4#include <linux/circ_buf.h>
   5#include <linux/ctype.h>
   6#include <linux/debugfs.h>
   7#include <linux/pm_runtime.h>
   8#include <linux/seq_file.h>
   9#include <drm/drmP.h>
  10
  11#include "v3d_drv.h"
  12#include "v3d_regs.h"
  13
  14#define REGDEF(reg) { reg, #reg }
  15struct v3d_reg_def {
  16        u32 reg;
  17        const char *name;
  18};
  19
  20static const struct v3d_reg_def v3d_hub_reg_defs[] = {
  21        REGDEF(V3D_HUB_AXICFG),
  22        REGDEF(V3D_HUB_UIFCFG),
  23        REGDEF(V3D_HUB_IDENT0),
  24        REGDEF(V3D_HUB_IDENT1),
  25        REGDEF(V3D_HUB_IDENT2),
  26        REGDEF(V3D_HUB_IDENT3),
  27        REGDEF(V3D_HUB_INT_STS),
  28        REGDEF(V3D_HUB_INT_MSK_STS),
  29
  30        REGDEF(V3D_MMU_CTL),
  31        REGDEF(V3D_MMU_VIO_ADDR),
  32        REGDEF(V3D_MMU_VIO_ID),
  33        REGDEF(V3D_MMU_DEBUG_INFO),
  34};
  35
  36static const struct v3d_reg_def v3d_gca_reg_defs[] = {
  37        REGDEF(V3D_GCA_SAFE_SHUTDOWN),
  38        REGDEF(V3D_GCA_SAFE_SHUTDOWN_ACK),
  39};
  40
  41static const struct v3d_reg_def v3d_core_reg_defs[] = {
  42        REGDEF(V3D_CTL_IDENT0),
  43        REGDEF(V3D_CTL_IDENT1),
  44        REGDEF(V3D_CTL_IDENT2),
  45        REGDEF(V3D_CTL_MISCCFG),
  46        REGDEF(V3D_CTL_INT_STS),
  47        REGDEF(V3D_CTL_INT_MSK_STS),
  48        REGDEF(V3D_CLE_CT0CS),
  49        REGDEF(V3D_CLE_CT0CA),
  50        REGDEF(V3D_CLE_CT0EA),
  51        REGDEF(V3D_CLE_CT1CS),
  52        REGDEF(V3D_CLE_CT1CA),
  53        REGDEF(V3D_CLE_CT1EA),
  54
  55        REGDEF(V3D_PTB_BPCA),
  56        REGDEF(V3D_PTB_BPCS),
  57
  58        REGDEF(V3D_GMP_STATUS),
  59        REGDEF(V3D_GMP_CFG),
  60        REGDEF(V3D_GMP_VIO_ADDR),
  61
  62        REGDEF(V3D_ERR_FDBGO),
  63        REGDEF(V3D_ERR_FDBGB),
  64        REGDEF(V3D_ERR_FDBGS),
  65        REGDEF(V3D_ERR_STAT),
  66};
  67
  68static const struct v3d_reg_def v3d_csd_reg_defs[] = {
  69        REGDEF(V3D_CSD_STATUS),
  70        REGDEF(V3D_CSD_CURRENT_CFG0),
  71        REGDEF(V3D_CSD_CURRENT_CFG1),
  72        REGDEF(V3D_CSD_CURRENT_CFG2),
  73        REGDEF(V3D_CSD_CURRENT_CFG3),
  74        REGDEF(V3D_CSD_CURRENT_CFG4),
  75        REGDEF(V3D_CSD_CURRENT_CFG5),
  76        REGDEF(V3D_CSD_CURRENT_CFG6),
  77};
  78
  79static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused)
  80{
  81        struct drm_info_node *node = (struct drm_info_node *)m->private;
  82        struct drm_device *dev = node->minor->dev;
  83        struct v3d_dev *v3d = to_v3d_dev(dev);
  84        int i, core;
  85
  86        for (i = 0; i < ARRAY_SIZE(v3d_hub_reg_defs); i++) {
  87                seq_printf(m, "%s (0x%04x): 0x%08x\n",
  88                           v3d_hub_reg_defs[i].name, v3d_hub_reg_defs[i].reg,
  89                           V3D_READ(v3d_hub_reg_defs[i].reg));
  90        }
  91
  92        if (v3d->ver < 41) {
  93                for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) {
  94                        seq_printf(m, "%s (0x%04x): 0x%08x\n",
  95                                   v3d_gca_reg_defs[i].name,
  96                                   v3d_gca_reg_defs[i].reg,
  97                                   V3D_GCA_READ(v3d_gca_reg_defs[i].reg));
  98                }
  99        }
 100
 101        for (core = 0; core < v3d->cores; core++) {
 102                for (i = 0; i < ARRAY_SIZE(v3d_core_reg_defs); i++) {
 103                        seq_printf(m, "core %d %s (0x%04x): 0x%08x\n",
 104                                   core,
 105                                   v3d_core_reg_defs[i].name,
 106                                   v3d_core_reg_defs[i].reg,
 107                                   V3D_CORE_READ(core,
 108                                                 v3d_core_reg_defs[i].reg));
 109                }
 110
 111                if (v3d_has_csd(v3d)) {
 112                        for (i = 0; i < ARRAY_SIZE(v3d_csd_reg_defs); i++) {
 113                                seq_printf(m, "core %d %s (0x%04x): 0x%08x\n",
 114                                           core,
 115                                           v3d_csd_reg_defs[i].name,
 116                                           v3d_csd_reg_defs[i].reg,
 117                                           V3D_CORE_READ(core,
 118                                                         v3d_csd_reg_defs[i].reg));
 119                        }
 120                }
 121        }
 122
 123        return 0;
 124}
 125
 126static int v3d_v3d_debugfs_ident(struct seq_file *m, void *unused)
 127{
 128        struct drm_info_node *node = (struct drm_info_node *)m->private;
 129        struct drm_device *dev = node->minor->dev;
 130        struct v3d_dev *v3d = to_v3d_dev(dev);
 131        u32 ident0, ident1, ident2, ident3, cores;
 132        int ret, core;
 133
 134        ret = pm_runtime_get_sync(v3d->dev);
 135        if (ret < 0)
 136                return ret;
 137
 138        ident0 = V3D_READ(V3D_HUB_IDENT0);
 139        ident1 = V3D_READ(V3D_HUB_IDENT1);
 140        ident2 = V3D_READ(V3D_HUB_IDENT2);
 141        ident3 = V3D_READ(V3D_HUB_IDENT3);
 142        cores = V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_NCORES);
 143
 144        seq_printf(m, "Revision:   %d.%d.%d.%d\n",
 145                   V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_TVER),
 146                   V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_REV),
 147                   V3D_GET_FIELD(ident3, V3D_HUB_IDENT3_IPREV),
 148                   V3D_GET_FIELD(ident3, V3D_HUB_IDENT3_IPIDX));
 149        seq_printf(m, "MMU:        %s\n",
 150                   (ident2 & V3D_HUB_IDENT2_WITH_MMU) ? "yes" : "no");
 151        seq_printf(m, "TFU:        %s\n",
 152                   (ident1 & V3D_HUB_IDENT1_WITH_TFU) ? "yes" : "no");
 153        seq_printf(m, "TSY:        %s\n",
 154                   (ident1 & V3D_HUB_IDENT1_WITH_TSY) ? "yes" : "no");
 155        seq_printf(m, "MSO:        %s\n",
 156                   (ident1 & V3D_HUB_IDENT1_WITH_MSO) ? "yes" : "no");
 157        seq_printf(m, "L3C:        %s (%dkb)\n",
 158                   (ident1 & V3D_HUB_IDENT1_WITH_L3C) ? "yes" : "no",
 159                   V3D_GET_FIELD(ident2, V3D_HUB_IDENT2_L3C_NKB));
 160
 161        for (core = 0; core < cores; core++) {
 162                u32 misccfg;
 163                u32 nslc, ntmu, qups;
 164
 165                ident0 = V3D_CORE_READ(core, V3D_CTL_IDENT0);
 166                ident1 = V3D_CORE_READ(core, V3D_CTL_IDENT1);
 167                ident2 = V3D_CORE_READ(core, V3D_CTL_IDENT2);
 168                misccfg = V3D_CORE_READ(core, V3D_CTL_MISCCFG);
 169
 170                nslc = V3D_GET_FIELD(ident1, V3D_IDENT1_NSLC);
 171                ntmu = V3D_GET_FIELD(ident1, V3D_IDENT1_NTMU);
 172                qups = V3D_GET_FIELD(ident1, V3D_IDENT1_QUPS);
 173
 174                seq_printf(m, "Core %d:\n", core);
 175                seq_printf(m, "  Revision:     %d.%d\n",
 176                           V3D_GET_FIELD(ident0, V3D_IDENT0_VER),
 177                           V3D_GET_FIELD(ident1, V3D_IDENT1_REV));
 178                seq_printf(m, "  Slices:       %d\n", nslc);
 179                seq_printf(m, "  TMUs:         %d\n", nslc * ntmu);
 180                seq_printf(m, "  QPUs:         %d\n", nslc * qups);
 181                seq_printf(m, "  Semaphores:   %d\n",
 182                           V3D_GET_FIELD(ident1, V3D_IDENT1_NSEM));
 183                seq_printf(m, "  BCG int:      %d\n",
 184                           (ident2 & V3D_IDENT2_BCG_INT) != 0);
 185                seq_printf(m, "  Override TMU: %d\n",
 186                           (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0);
 187        }
 188
 189        pm_runtime_mark_last_busy(v3d->dev);
 190        pm_runtime_put_autosuspend(v3d->dev);
 191
 192        return 0;
 193}
 194
 195static int v3d_debugfs_bo_stats(struct seq_file *m, void *unused)
 196{
 197        struct drm_info_node *node = (struct drm_info_node *)m->private;
 198        struct drm_device *dev = node->minor->dev;
 199        struct v3d_dev *v3d = to_v3d_dev(dev);
 200
 201        mutex_lock(&v3d->bo_lock);
 202        seq_printf(m, "allocated bos:          %d\n",
 203                   v3d->bo_stats.num_allocated);
 204        seq_printf(m, "allocated bo size (kb): %ld\n",
 205                   (long)v3d->bo_stats.pages_allocated << (PAGE_SHIFT - 10));
 206        mutex_unlock(&v3d->bo_lock);
 207
 208        return 0;
 209}
 210
 211static int v3d_measure_clock(struct seq_file *m, void *unused)
 212{
 213        struct drm_info_node *node = (struct drm_info_node *)m->private;
 214        struct drm_device *dev = node->minor->dev;
 215        struct v3d_dev *v3d = to_v3d_dev(dev);
 216        uint32_t cycles;
 217        int core = 0;
 218        int measure_ms = 1000;
 219        int ret;
 220
 221        ret = pm_runtime_get_sync(v3d->dev);
 222        if (ret < 0)
 223                return ret;
 224
 225        if (v3d->ver >= 40) {
 226                V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
 227                               V3D_SET_FIELD(V3D_PCTR_CYCLE_COUNT,
 228                                             V3D_PCTR_S0));
 229                V3D_CORE_WRITE(core, V3D_V4_PCTR_0_CLR, 1);
 230                V3D_CORE_WRITE(core, V3D_V4_PCTR_0_EN, 1);
 231        } else {
 232                V3D_CORE_WRITE(core, V3D_V3_PCTR_0_PCTRS0,
 233                               V3D_PCTR_CYCLE_COUNT);
 234                V3D_CORE_WRITE(core, V3D_V3_PCTR_0_CLR, 1);
 235                V3D_CORE_WRITE(core, V3D_V3_PCTR_0_EN,
 236                               V3D_V3_PCTR_0_EN_ENABLE |
 237                               1);
 238        }
 239        msleep(measure_ms);
 240        cycles = V3D_CORE_READ(core, V3D_PCTR_0_PCTR0);
 241
 242        seq_printf(m, "cycles: %d (%d.%d Mhz)\n",
 243                   cycles,
 244                   cycles / (measure_ms * 1000),
 245                   (cycles / (measure_ms * 100)) % 10);
 246
 247        pm_runtime_mark_last_busy(v3d->dev);
 248        pm_runtime_put_autosuspend(v3d->dev);
 249
 250        return 0;
 251}
 252
 253static const struct drm_info_list v3d_debugfs_list[] = {
 254        {"v3d_ident", v3d_v3d_debugfs_ident, 0},
 255        {"v3d_regs", v3d_v3d_debugfs_regs, 0},
 256        {"measure_clock", v3d_measure_clock, 0},
 257        {"bo_stats", v3d_debugfs_bo_stats, 0},
 258};
 259
 260int
 261v3d_debugfs_init(struct drm_minor *minor)
 262{
 263        return drm_debugfs_create_files(v3d_debugfs_list,
 264                                        ARRAY_SIZE(v3d_debugfs_list),
 265                                        minor->debugfs_root, minor);
 266}
 267