Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
  4 */
  5
  6#define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
  7
  8#include <generated/utsrelease.h>
  9
 10#include "msm_disp_snapshot.h"
 11
 12static void msm_disp_state_dump_regs(u32 **reg, u32 aligned_len, void __iomem *base_addr)
 13{
 14	u32 len_padded;
 15	u32 num_rows;
 16	u32 x0, x4, x8, xc;
 17	void __iomem *addr;
 18	u32 *dump_addr = NULL;
 19	void __iomem *end_addr;
 20	int i;
 21
 22	len_padded = aligned_len * REG_DUMP_ALIGN;
 23	num_rows = aligned_len / REG_DUMP_ALIGN;
 24
 25	addr = base_addr;
 26	end_addr = base_addr + aligned_len;
 27
 28	if (!(*reg))
 29		*reg = kzalloc(len_padded, GFP_KERNEL);
 30
 31	if (*reg)
 32		dump_addr = *reg;
 33
 34	for (i = 0; i < num_rows; i++) {
 35		x0 = (addr < end_addr) ? readl_relaxed(addr + 0x0) : 0;
 36		x4 = (addr + 0x4 < end_addr) ? readl_relaxed(addr + 0x4) : 0;
 37		x8 = (addr + 0x8 < end_addr) ? readl_relaxed(addr + 0x8) : 0;
 38		xc = (addr + 0xc < end_addr) ? readl_relaxed(addr + 0xc) : 0;
 39
 40		if (dump_addr) {
 41			dump_addr[i * 4] = x0;
 42			dump_addr[i * 4 + 1] = x4;
 43			dump_addr[i * 4 + 2] = x8;
 44			dump_addr[i * 4 + 3] = xc;
 45		}
 46
 47		addr += REG_DUMP_ALIGN;
 48	}
 49}
 50
 51static void msm_disp_state_print_regs(u32 **reg, u32 len, void __iomem *base_addr,
 52		struct drm_printer *p)
 53{
 54	int i;
 55	u32 *dump_addr = NULL;
 56	void __iomem *addr;
 57	u32 num_rows;
 58
 59	addr = base_addr;
 60	num_rows = len / REG_DUMP_ALIGN;
 61
 62	if (*reg)
 63		dump_addr = *reg;
 64
 65	for (i = 0; i < num_rows; i++) {
 66		drm_printf(p, "0x%lx : %08x %08x %08x %08x\n",
 67				(unsigned long)(addr - base_addr),
 68				dump_addr[i * 4], dump_addr[i * 4 + 1],
 69				dump_addr[i * 4 + 2], dump_addr[i * 4 + 3]);
 70		addr += REG_DUMP_ALIGN;
 71	}
 72}
 73
 74void msm_disp_state_print(struct msm_disp_state *state, struct drm_printer *p)
 75{
 76	struct msm_disp_state_block *block, *tmp;
 77
 78	if (!p) {
 79		DRM_ERROR("invalid drm printer\n");
 80		return;
 81	}
 82
 83	drm_printf(p, "---\n");
 84	drm_printf(p, "kernel: " UTS_RELEASE "\n");
 85	drm_printf(p, "module: " KBUILD_MODNAME "\n");
 86	drm_printf(p, "dpu devcoredump\n");
 87	drm_printf(p, "time: %lld.%09ld\n",
 88		state->time.tv_sec, state->time.tv_nsec);
 89
 90	list_for_each_entry_safe(block, tmp, &state->blocks, node) {
 91		drm_printf(p, "====================%s================\n", block->name);
 92		msm_disp_state_print_regs(&block->state, block->size, block->base_addr, p);
 93	}
 94
 95	drm_printf(p, "===================dpu drm state================\n");
 96
 97	if (state->atomic_state)
 98		drm_atomic_print_new_state(state->atomic_state, p);
 99}
100
101static void msm_disp_capture_atomic_state(struct msm_disp_state *disp_state)
102{
103	struct drm_device *ddev;
104	struct drm_modeset_acquire_ctx ctx;
105
106	ktime_get_real_ts64(&disp_state->time);
107
108	ddev = disp_state->drm_dev;
109
110	drm_modeset_acquire_init(&ctx, 0);
111
112	while (drm_modeset_lock_all_ctx(ddev, &ctx) != 0)
113		drm_modeset_backoff(&ctx);
114
115	disp_state->atomic_state = drm_atomic_helper_duplicate_state(ddev,
116			&ctx);
117	drm_modeset_drop_locks(&ctx);
118	drm_modeset_acquire_fini(&ctx);
119}
120
121void msm_disp_snapshot_capture_state(struct msm_disp_state *disp_state)
122{
123	struct msm_drm_private *priv;
124	struct drm_device *drm_dev;
125	struct msm_kms *kms;
126	int i;
127
128	drm_dev = disp_state->drm_dev;
129	priv = drm_dev->dev_private;
130	kms = priv->kms;
131
132	for (i = 0; i < ARRAY_SIZE(priv->dp); i++) {
133		if (!priv->dp[i])
134			continue;
135
136		msm_dp_snapshot(disp_state, priv->dp[i]);
137	}
138
139	for (i = 0; i < ARRAY_SIZE(priv->dsi); i++) {
140		if (!priv->dsi[i])
141			continue;
142
143		msm_dsi_snapshot(disp_state, priv->dsi[i]);
144	}
145
146	if (kms->funcs->snapshot)
147		kms->funcs->snapshot(disp_state, kms);
148
149	msm_disp_capture_atomic_state(disp_state);
150}
151
152void msm_disp_state_free(void *data)
153{
154	struct msm_disp_state *disp_state = data;
155	struct msm_disp_state_block *block, *tmp;
156
157	if (disp_state->atomic_state) {
158		drm_atomic_state_put(disp_state->atomic_state);
159		disp_state->atomic_state = NULL;
160	}
161
162	list_for_each_entry_safe(block, tmp, &disp_state->blocks, node) {
163		list_del(&block->node);
164		kfree(block->state);
165		kfree(block);
166	}
167
168	kfree(disp_state);
169}
170
171void msm_disp_snapshot_add_block(struct msm_disp_state *disp_state, u32 len,
172		void __iomem *base_addr, const char *fmt, ...)
173{
174	struct msm_disp_state_block *new_blk;
175	struct va_format vaf;
176	va_list va;
177
178	new_blk = kzalloc(sizeof(struct msm_disp_state_block), GFP_KERNEL);
179	if (!new_blk)
180		return;
181
182	va_start(va, fmt);
183
184	vaf.fmt = fmt;
185	vaf.va = &va;
186	snprintf(new_blk->name, sizeof(new_blk->name), "%pV", &vaf);
187
188	va_end(va);
189
190	INIT_LIST_HEAD(&new_blk->node);
191	new_blk->size = ALIGN(len, REG_DUMP_ALIGN);
192	new_blk->base_addr = base_addr;
193
194	msm_disp_state_dump_regs(&new_blk->state, new_blk->size, base_addr);
195	list_add(&new_blk->node, &disp_state->blocks);
196}