162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/types.h> 662306a36Sopenharmony_ci#include <linux/debugfs.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <drm/drm_debugfs.h> 962306a36Sopenharmony_ci#include <drm/drm_file.h> 1062306a36Sopenharmony_ci#include <drm/drm_print.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "a5xx_gpu.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic void pfp_print(struct msm_gpu *gpu, struct drm_printer *p) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci int i; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci drm_printf(p, "PFP state:\n"); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci for (i = 0; i < 36; i++) { 2162306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_PFP_STAT_ADDR, i); 2262306a36Sopenharmony_ci drm_printf(p, " %02x: %08x\n", i, 2362306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA)); 2462306a36Sopenharmony_ci } 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic void me_print(struct msm_gpu *gpu, struct drm_printer *p) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci int i; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci drm_printf(p, "ME state:\n"); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci for (i = 0; i < 29; i++) { 3462306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_ME_STAT_ADDR, i); 3562306a36Sopenharmony_ci drm_printf(p, " %02x: %08x\n", i, 3662306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_ME_STAT_DATA)); 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void meq_print(struct msm_gpu *gpu, struct drm_printer *p) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci int i; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci drm_printf(p, "MEQ state:\n"); 4562306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_MEQ_DBG_ADDR, 0); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci for (i = 0; i < 64; i++) { 4862306a36Sopenharmony_ci drm_printf(p, " %02x: %08x\n", i, 4962306a36Sopenharmony_ci gpu_read(gpu, REG_A5XX_CP_MEQ_DBG_DATA)); 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic void roq_print(struct msm_gpu *gpu, struct drm_printer *p) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci int i; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci drm_printf(p, "ROQ state:\n"); 5862306a36Sopenharmony_ci gpu_write(gpu, REG_A5XX_CP_ROQ_DBG_ADDR, 0); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci for (i = 0; i < 512 / 4; i++) { 6162306a36Sopenharmony_ci uint32_t val[4]; 6262306a36Sopenharmony_ci int j; 6362306a36Sopenharmony_ci for (j = 0; j < 4; j++) 6462306a36Sopenharmony_ci val[j] = gpu_read(gpu, REG_A5XX_CP_ROQ_DBG_DATA); 6562306a36Sopenharmony_ci drm_printf(p, " %02x: %08x %08x %08x %08x\n", i, 6662306a36Sopenharmony_ci val[0], val[1], val[2], val[3]); 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic int show(struct seq_file *m, void *arg) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct drm_info_node *node = m->private; 7362306a36Sopenharmony_ci struct drm_device *dev = node->minor->dev; 7462306a36Sopenharmony_ci struct msm_drm_private *priv = dev->dev_private; 7562306a36Sopenharmony_ci struct drm_printer p = drm_seq_file_printer(m); 7662306a36Sopenharmony_ci void (*show)(struct msm_gpu *gpu, struct drm_printer *p) = 7762306a36Sopenharmony_ci node->info_ent->data; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci show(priv->gpu, &p); 8062306a36Sopenharmony_ci return 0; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#define ENT(n) { .name = #n, .show = show, .data = n ##_print } 8462306a36Sopenharmony_cistatic struct drm_info_list a5xx_debugfs_list[] = { 8562306a36Sopenharmony_ci ENT(pfp), 8662306a36Sopenharmony_ci ENT(me), 8762306a36Sopenharmony_ci ENT(meq), 8862306a36Sopenharmony_ci ENT(roq), 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* for debugfs files that can be written to, we can't use drm helper: */ 9262306a36Sopenharmony_cistatic int 9362306a36Sopenharmony_cireset_set(void *data, u64 val) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct drm_device *dev = data; 9662306a36Sopenharmony_ci struct msm_drm_private *priv = dev->dev_private; 9762306a36Sopenharmony_ci struct msm_gpu *gpu = priv->gpu; 9862306a36Sopenharmony_ci struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); 9962306a36Sopenharmony_ci struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 10262306a36Sopenharmony_ci return -EINVAL; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* TODO do we care about trying to make sure the GPU is idle? 10562306a36Sopenharmony_ci * Since this is just a debug feature limited to CAP_SYS_ADMIN, 10662306a36Sopenharmony_ci * maybe it is fine to let the user keep both pieces if they 10762306a36Sopenharmony_ci * try to reset an active GPU. 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci mutex_lock(&gpu->lock); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci release_firmware(adreno_gpu->fw[ADRENO_FW_PM4]); 11362306a36Sopenharmony_ci adreno_gpu->fw[ADRENO_FW_PM4] = NULL; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci release_firmware(adreno_gpu->fw[ADRENO_FW_PFP]); 11662306a36Sopenharmony_ci adreno_gpu->fw[ADRENO_FW_PFP] = NULL; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (a5xx_gpu->pm4_bo) { 11962306a36Sopenharmony_ci msm_gem_unpin_iova(a5xx_gpu->pm4_bo, gpu->aspace); 12062306a36Sopenharmony_ci drm_gem_object_put(a5xx_gpu->pm4_bo); 12162306a36Sopenharmony_ci a5xx_gpu->pm4_bo = NULL; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (a5xx_gpu->pfp_bo) { 12562306a36Sopenharmony_ci msm_gem_unpin_iova(a5xx_gpu->pfp_bo, gpu->aspace); 12662306a36Sopenharmony_ci drm_gem_object_put(a5xx_gpu->pfp_bo); 12762306a36Sopenharmony_ci a5xx_gpu->pfp_bo = NULL; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci gpu->needs_hw_init = true; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci pm_runtime_get_sync(&gpu->pdev->dev); 13362306a36Sopenharmony_ci gpu->funcs->recover(gpu); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci pm_runtime_put_sync(&gpu->pdev->dev); 13662306a36Sopenharmony_ci mutex_unlock(&gpu->lock); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return 0; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n"); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_civoid a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct drm_device *dev; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (!minor) 14962306a36Sopenharmony_ci return; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci dev = minor->dev; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci drm_debugfs_create_files(a5xx_debugfs_list, 15462306a36Sopenharmony_ci ARRAY_SIZE(a5xx_debugfs_list), 15562306a36Sopenharmony_ci minor->debugfs_root, minor); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci debugfs_create_file_unsafe("reset", S_IWUGO, minor->debugfs_root, dev, 15862306a36Sopenharmony_ci &reset_fops); 15962306a36Sopenharmony_ci} 160