Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
0004  */
0005 
0006 #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
0007 
0008 #include <generated/utsrelease.h>
0009 
0010 #include "msm_disp_snapshot.h"
0011 
0012 static void msm_disp_state_dump_regs(u32 **reg, u32 aligned_len, void __iomem *base_addr)
0013 {
0014     u32 len_padded;
0015     u32 num_rows;
0016     u32 x0, x4, x8, xc;
0017     void __iomem *addr;
0018     u32 *dump_addr = NULL;
0019     void __iomem *end_addr;
0020     int i;
0021 
0022     len_padded = aligned_len * REG_DUMP_ALIGN;
0023     num_rows = aligned_len / REG_DUMP_ALIGN;
0024 
0025     addr = base_addr;
0026     end_addr = base_addr + aligned_len;
0027 
0028     if (!(*reg))
0029         *reg = kzalloc(len_padded, GFP_KERNEL);
0030 
0031     if (*reg)
0032         dump_addr = *reg;
0033 
0034     for (i = 0; i < num_rows; i++) {
0035         x0 = (addr < end_addr) ? readl_relaxed(addr + 0x0) : 0;
0036         x4 = (addr + 0x4 < end_addr) ? readl_relaxed(addr + 0x4) : 0;
0037         x8 = (addr + 0x8 < end_addr) ? readl_relaxed(addr + 0x8) : 0;
0038         xc = (addr + 0xc < end_addr) ? readl_relaxed(addr + 0xc) : 0;
0039 
0040         if (dump_addr) {
0041             dump_addr[i * 4] = x0;
0042             dump_addr[i * 4 + 1] = x4;
0043             dump_addr[i * 4 + 2] = x8;
0044             dump_addr[i * 4 + 3] = xc;
0045         }
0046 
0047         addr += REG_DUMP_ALIGN;
0048     }
0049 }
0050 
0051 static void msm_disp_state_print_regs(u32 **reg, u32 len, void __iomem *base_addr,
0052         struct drm_printer *p)
0053 {
0054     int i;
0055     u32 *dump_addr = NULL;
0056     void __iomem *addr;
0057     u32 num_rows;
0058 
0059     addr = base_addr;
0060     num_rows = len / REG_DUMP_ALIGN;
0061 
0062     if (*reg)
0063         dump_addr = *reg;
0064 
0065     for (i = 0; i < num_rows; i++) {
0066         drm_printf(p, "0x%lx : %08x %08x %08x %08x\n",
0067                 (unsigned long)(addr - base_addr),
0068                 dump_addr[i * 4], dump_addr[i * 4 + 1],
0069                 dump_addr[i * 4 + 2], dump_addr[i * 4 + 3]);
0070         addr += REG_DUMP_ALIGN;
0071     }
0072 }
0073 
0074 void msm_disp_state_print(struct msm_disp_state *state, struct drm_printer *p)
0075 {
0076     struct msm_disp_state_block *block, *tmp;
0077 
0078     if (!p) {
0079         DRM_ERROR("invalid drm printer\n");
0080         return;
0081     }
0082 
0083     drm_printf(p, "---\n");
0084     drm_printf(p, "kernel: " UTS_RELEASE "\n");
0085     drm_printf(p, "module: " KBUILD_MODNAME "\n");
0086     drm_printf(p, "dpu devcoredump\n");
0087     drm_printf(p, "time: %lld.%09ld\n",
0088         state->time.tv_sec, state->time.tv_nsec);
0089 
0090     list_for_each_entry_safe(block, tmp, &state->blocks, node) {
0091         drm_printf(p, "====================%s================\n", block->name);
0092         msm_disp_state_print_regs(&block->state, block->size, block->base_addr, p);
0093     }
0094 
0095     drm_printf(p, "===================dpu drm state================\n");
0096 
0097     if (state->atomic_state)
0098         drm_atomic_print_new_state(state->atomic_state, p);
0099 }
0100 
0101 static void msm_disp_capture_atomic_state(struct msm_disp_state *disp_state)
0102 {
0103     struct drm_device *ddev;
0104     struct drm_modeset_acquire_ctx ctx;
0105 
0106     ktime_get_real_ts64(&disp_state->time);
0107 
0108     ddev = disp_state->drm_dev;
0109 
0110     drm_modeset_acquire_init(&ctx, 0);
0111 
0112     while (drm_modeset_lock_all_ctx(ddev, &ctx) != 0)
0113         drm_modeset_backoff(&ctx);
0114 
0115     disp_state->atomic_state = drm_atomic_helper_duplicate_state(ddev,
0116             &ctx);
0117     drm_modeset_drop_locks(&ctx);
0118     drm_modeset_acquire_fini(&ctx);
0119 }
0120 
0121 void msm_disp_snapshot_capture_state(struct msm_disp_state *disp_state)
0122 {
0123     struct msm_drm_private *priv;
0124     struct drm_device *drm_dev;
0125     struct msm_kms *kms;
0126     int i;
0127 
0128     drm_dev = disp_state->drm_dev;
0129     priv = drm_dev->dev_private;
0130     kms = priv->kms;
0131 
0132     for (i = 0; i < ARRAY_SIZE(priv->dp); i++) {
0133         if (!priv->dp[i])
0134             continue;
0135 
0136         msm_dp_snapshot(disp_state, priv->dp[i]);
0137     }
0138 
0139     for (i = 0; i < ARRAY_SIZE(priv->dsi); i++) {
0140         if (!priv->dsi[i])
0141             continue;
0142 
0143         msm_dsi_snapshot(disp_state, priv->dsi[i]);
0144     }
0145 
0146     if (kms->funcs->snapshot)
0147         kms->funcs->snapshot(disp_state, kms);
0148 
0149     msm_disp_capture_atomic_state(disp_state);
0150 }
0151 
0152 void msm_disp_state_free(void *data)
0153 {
0154     struct msm_disp_state *disp_state = data;
0155     struct msm_disp_state_block *block, *tmp;
0156 
0157     if (disp_state->atomic_state) {
0158         drm_atomic_state_put(disp_state->atomic_state);
0159         disp_state->atomic_state = NULL;
0160     }
0161 
0162     list_for_each_entry_safe(block, tmp, &disp_state->blocks, node) {
0163         list_del(&block->node);
0164         kfree(block->state);
0165         kfree(block);
0166     }
0167 
0168     kfree(disp_state);
0169 }
0170 
0171 void msm_disp_snapshot_add_block(struct msm_disp_state *disp_state, u32 len,
0172         void __iomem *base_addr, const char *fmt, ...)
0173 {
0174     struct msm_disp_state_block *new_blk;
0175     struct va_format vaf;
0176     va_list va;
0177 
0178     new_blk = kzalloc(sizeof(struct msm_disp_state_block), GFP_KERNEL);
0179     if (!new_blk)
0180         return;
0181 
0182     va_start(va, fmt);
0183 
0184     vaf.fmt = fmt;
0185     vaf.va = &va;
0186     snprintf(new_blk->name, sizeof(new_blk->name), "%pV", &vaf);
0187 
0188     va_end(va);
0189 
0190     INIT_LIST_HEAD(&new_blk->node);
0191     new_blk->size = ALIGN(len, REG_DUMP_ALIGN);
0192     new_blk->base_addr = base_addr;
0193 
0194     msm_disp_state_dump_regs(&new_blk->state, new_blk->size, base_addr);
0195     list_add(&new_blk->node, &disp_state->blocks);
0196 }