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