drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c
Extension
.c
Size
4904 bytes
Lines
206
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
 */

#define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__

#include <linux/utsname.h>

#include "msm_disp_snapshot.h"

static void msm_disp_state_dump_regs(u32 **reg, u32 len, void __iomem *base_addr)
{
	u32 len_padded;
	u32 num_rows;
	u32 x0, x4, x8, xc;
	void __iomem *addr;
	u32 *dump_addr = NULL;
	void __iomem *end_addr;
	int i;

	len_padded = round_up(len, REG_DUMP_ALIGN);
	num_rows = DIV_ROUND_UP(len, REG_DUMP_ALIGN);

	addr = base_addr;
	end_addr = base_addr + len;

	*reg = kvzalloc(len_padded, GFP_KERNEL);
	if (!*reg)
		return;

	dump_addr = *reg;
	for (i = 0; i < num_rows; i++) {
		x0 = (addr < end_addr) ? readl_relaxed(addr + 0x0) : 0;
		x4 = (addr + 0x4 < end_addr) ? readl_relaxed(addr + 0x4) : 0;
		x8 = (addr + 0x8 < end_addr) ? readl_relaxed(addr + 0x8) : 0;
		xc = (addr + 0xc < end_addr) ? readl_relaxed(addr + 0xc) : 0;

		dump_addr[i * 4] = x0;
		dump_addr[i * 4 + 1] = x4;
		dump_addr[i * 4 + 2] = x8;
		dump_addr[i * 4 + 3] = xc;

		addr += REG_DUMP_ALIGN;
	}
}

static void msm_disp_state_print_regs(const u32 *dump_addr, u32 len,
		void __iomem *base_addr, struct drm_printer *p)
{
	void __iomem *addr, *end_addr;
	int i;
	u32 num_rows;

	if (!dump_addr) {
		drm_printf(p, "Registers not stored\n");
		return;
	}

	addr = base_addr;
	end_addr = base_addr + len;
	num_rows = len / REG_DUMP_ALIGN;

	for (i = 0; i < num_rows; i++) {
		drm_printf(p, "0x%lx : %08x %08x %08x %08x\n",
				(unsigned long)(addr - base_addr),
				dump_addr[i * 4], dump_addr[i * 4 + 1],
				dump_addr[i * 4 + 2], dump_addr[i * 4 + 3]);
		addr += REG_DUMP_ALIGN;
	}

	if (addr != end_addr) {
		drm_printf(p, "0x%lx : %08x",
			   (unsigned long)(addr - base_addr),
			   dump_addr[i * 4]);
		if (addr + 0x4 < end_addr)
			drm_printf(p, " %08x", dump_addr[i * 4 + 1]);
		if (addr + 0x8 < end_addr)
			drm_printf(p, " %08x", dump_addr[i * 4 + 2]);
		drm_printf(p, "\n");
	}
}

void msm_disp_state_print(struct msm_disp_state *state, struct drm_printer *p)
{
	struct msm_disp_state_block *block, *tmp;

	if (!p) {
		DRM_ERROR("invalid drm printer\n");
		return;

Annotation

Implementation Notes