Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 06c674cf authored by Adrian Salido-Moreno's avatar Adrian Salido-Moreno
Browse files

msm: mdss: dump MDP state through debugfs



Add debugfs file to dump complete MDP state and gives a complete
snapshot of MDP state.

Change-Id: I9c3b5ebf9981a7197bff011c13cc3aeea7af5b78
Signed-off-by: default avatarAdrian Salido-Moreno <adrianm@codeaurora.org>
parent 41efd125
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ mdss-mdp-objs += mdss_mdp_overlay.o
mdss-mdp-objs += mdss_mdp_splash_logo.o
mdss-mdp-objs += mdss_mdp_wb.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_mdp_debug.o

ifeq ($(CONFIG_FB_MSM_MDSS),y)
obj-$(CONFIG_DEBUG_FS) += mdss_debug.o mdss_debug_xlog.o
+15 −0
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
#define MDSS_DEBUG_H

#include <stdarg.h>
#include <linux/debugfs.h>
#include <linux/list.h>
#include <linux/mdss_io_util.h>

#include "mdss.h"
@@ -67,6 +69,19 @@ struct mdss_debug_data {
	struct debug_log logd;
};

#define DEFINE_MDSS_DEBUGFS_SEQ_FOPS(__prefix)				\
static int __prefix ## _open(struct inode *inode, struct file *file)	\
{									\
	return single_open(file, __prefix ## _show, inode->i_private);	\
}									\
static const struct file_operations __prefix ## _fops = {		\
	.owner = THIS_MODULE,						\
	.open = __prefix ## _open,					\
	.release = single_release,					\
	.read = seq_read,						\
	.llseek = seq_lseek,						\
};

int mdss_debugfs_init(struct mdss_data_type *mdata);
int mdss_debugfs_remove(struct mdss_data_type *mdata);
int mdss_debug_register_base(const char *name, void __iomem *base,
+7 −0
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@
#include "mdss_mdp.h"
#include "mdss_panel.h"
#include "mdss_debug.h"
#include "mdss_mdp_debug.h"

#define CREATE_TRACE_POINTS
#include "mdss_mdp_trace.h"
@@ -1131,6 +1132,12 @@ static int mdss_mdp_debug_init(struct mdss_data_type *mdata)
	if (rc)
		return rc;

	rc = mdss_mdp_debugfs_init(mdata);
	if (rc) {
		mdss_debugfs_remove(mdata);
		return rc;
	}

	mdss_debug_register_io("mdp", &mdata->mdss_io);
	mdss_debug_register_io("vbif", &mdata->vbif_io);

+202 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/debugfs.h>
#include <linux/seq_file.h>

#include "mdss_mdp.h"
#include "mdss_panel.h"
#include "mdss_debug.h"
#include "mdss_mdp_debug.h"

static void __dump_pipe(struct seq_file *s, struct mdss_mdp_pipe *pipe)
{
	struct mdss_mdp_img_data *buf;
	int format;
	int smps[4];

	seq_printf(s, "\nSSPP #%d type=%s ndx=%x flags=0x%08x play_cnt=%u\n",
			pipe->num, mdss_mdp_pipetype2str(pipe->type),
			pipe->ndx, pipe->flags, pipe->play_cnt);
	seq_printf(s, "\tstage=%d alpha=0x%x transp=0x%x blend_op=%d\n",
			pipe->mixer_stage, pipe->alpha,
			pipe->transp, pipe->blend_op);

	format = pipe->src_fmt->format;
	seq_printf(s, "\tsrc w=%d h=%d format=%d (%s)\n",
			pipe->img_width, pipe->img_height, format,
			mdss_mdp_format2str(format));
	seq_printf(s, "\tsrc_rect x=%d y=%d w=%d h=%d H.dec=%d V.dec=%d\n",
			pipe->src.x, pipe->src.y, pipe->src.w, pipe->src.h,
			pipe->horz_deci, pipe->vert_deci);
	seq_printf(s, "\tdst_rect x=%d y=%d w=%d h=%d\n",
			pipe->dst.x, pipe->dst.y, pipe->dst.w, pipe->dst.h);

	smps[0] = bitmap_weight(pipe->smp_map[0].allocated,
			MAX_DRV_SUP_MMB_BLKS);
	smps[1] = bitmap_weight(pipe->smp_map[1].allocated,
			MAX_DRV_SUP_MMB_BLKS);
	smps[2] = bitmap_weight(pipe->smp_map[0].reserved,
			MAX_DRV_SUP_MMB_BLKS);
	smps[3] = bitmap_weight(pipe->smp_map[1].reserved,
			MAX_DRV_SUP_MMB_BLKS);

	seq_printf(s, "\tSMP allocated=[%d %d] reserved=[%d %d]\n",
			smps[0], smps[1], smps[2], smps[3]);

	seq_puts(s, "Data:\n");
	if (pipe->front_buf.num_planes) {
		buf = pipe->front_buf.p;
		seq_printf(s, "\tfront_buf ihdl=0x%p addr=%pa size=%lu\n",
				buf->srcp_ihdl, &buf->addr, buf->len);
	}

	if (pipe->back_buf.num_planes) {
		buf = pipe->back_buf.p;
		seq_printf(s, "\tback_buf ihdl=0x%p addr=%pa size=%lu\n",
				buf->srcp_ihdl, &buf->addr, buf->len);
	}
}

static void __dump_mixer(struct seq_file *s, struct mdss_mdp_mixer *mixer)
{
	struct mdss_mdp_pipe *pipe;
	int i, cnt = 0;

	if (!mixer)
		return;

	seq_printf(s, "\n%s Mixer #%d  res=%dx%d  %s\n",
		mixer->type == MDSS_MDP_MIXER_TYPE_INTF ? "Intf" : "Writeback",
		mixer->num, mixer->width, mixer->height,
		mixer->cursor_enabled ? "w/cursor" : "");

	for (i = 0; i < ARRAY_SIZE(mixer->stage_pipe); i++) {
		pipe = mixer->stage_pipe[i];
		if (pipe) {
			__dump_pipe(s, pipe);
			cnt++;
		}
	}

	seq_printf(s, "\nTotal pipes=%d\n", cnt);
}

static void __dump_ctl(struct seq_file *s, struct mdss_mdp_ctl *ctl)
{
	struct mdss_mdp_perf_params *perf;
	if (!ctl->power_on)
		return;

	seq_printf(s, "\n--[ Control path #%d - ", ctl->num);

	if (ctl->panel_data) {
		seq_puts(s, mdss_panel2str(ctl->panel_data->panel_info.type));
	} else {
		struct mdss_mdp_mixer *mixer;
		mixer = ctl->mixer_left;
		if (mixer) {
			seq_printf(s, "%s%d",
					(mixer->rotator_mode ? "rot" : "wb"),
					mixer->num);
		} else {
			seq_puts(s, "unknown");
		}
	}
	perf = &ctl->cur_perf;
	seq_puts(s, "]--\n");
	seq_printf(s, "MDP Clk=%u  Final BW=%llu\n",
			perf->mdp_clk_rate,
			perf->bw_ctl);
	seq_printf(s, "Play Count=%u  Underrun Count=%u\n",
			ctl->play_cnt, ctl->underrun_cnt);

	__dump_mixer(s, ctl->mixer_left);
	__dump_mixer(s, ctl->mixer_right);
}

static int __dump_mdp(struct seq_file *s, struct mdss_data_type *mdata)
{
	struct mdss_mdp_ctl *ctl;
	int i, ignore_ndx = -1;

	for (i = 0; i < mdata->nctl; i++) {
		ctl = mdata->ctl_off + i;
		/* ignore slave ctl in split display case */
		if (ctl->num == ignore_ndx)
			continue;
		if (ctl->mixer_right && (ctl->mixer_right->ctl != ctl))
			ignore_ndx = ctl->mixer_right->ctl->num;
		__dump_ctl(s, ctl);
	}
	return 0;
}

#define DUMP_CHUNK 256
#define DUMP_SIZE SZ_32K
void mdss_mdp_dump(struct mdss_data_type *mdata)
{
	struct seq_file s = {
		.size = DUMP_SIZE - 1,
	};
	int i;

	s.buf = kzalloc(DUMP_SIZE, GFP_KERNEL);
	if (!s.buf)
		return;

	__dump_mdp(&s, mdata);
	seq_puts(&s, "\n");

	pr_info("MDP DUMP\n------------------------\n");
	for (i = 0; i < s.count; i += DUMP_CHUNK) {
		if ((s.count - i) > DUMP_CHUNK) {
			char c = s.buf[i + DUMP_CHUNK];
			s.buf[i + DUMP_CHUNK] = 0;
			pr_cont("%s", s.buf + i);
			s.buf[i + DUMP_CHUNK] = c;
		} else {
			s.buf[s.count] = 0;
			pr_cont("%s", s.buf + i);
		}
	}

	kfree(s.buf);
}

#ifdef CONFIG_DEBUG_FS
static int mdss_debugfs_dump_show(struct seq_file *s, void *v)
{
	struct mdss_data_type *mdata = (struct mdss_data_type *)s->private;

	return __dump_mdp(s, mdata);
}
DEFINE_MDSS_DEBUGFS_SEQ_FOPS(mdss_debugfs_dump);

int mdss_mdp_debugfs_init(struct mdss_data_type *mdata)
{
	struct mdss_debug_data *mdd;

	if (!mdata)
		return -ENODEV;

	mdd = mdata->debug_inf.debug_data;
	if (!mdd)
		return -ENOENT;

	debugfs_create_file("dump", 0644, mdd->root, mdata,
			&mdss_debugfs_dump_fops);

	return 0;
}
#endif
+81 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#ifndef MDSS_MDP_DEBUG_H
#define MDSS_MDP_DEBUG_H

#include <linux/msm_mdp.h>
#include <linux/stringify.h>

#include "mdss.h"
#include "mdss_mdp.h"

static inline const char *mdss_mdp_pipetype2str(u32 ptype)
{
	static const char const *strings[] = {
#define PIPE_TYPE(t) [MDSS_MDP_PIPE_TYPE_ ## t] = __stringify(t)
		PIPE_TYPE(VIG),
		PIPE_TYPE(RGB),
		PIPE_TYPE(DMA),
#undef PIPE_TYPE
	};

	if (ptype >= ARRAY_SIZE(strings))
		return "UNKOWN";

	return strings[ptype];
}

static inline const char *mdss_mdp_format2str(u32 format)
{
	static const char const *strings[] = {
#define FORMAT_NAME(f) [MDP_ ## f] = __stringify(f)
		FORMAT_NAME(RGB_565),
		FORMAT_NAME(BGR_565),
		FORMAT_NAME(RGB_888),
		FORMAT_NAME(BGR_888),
		FORMAT_NAME(RGBX_8888),
		FORMAT_NAME(RGBA_8888),
		FORMAT_NAME(ARGB_8888),
		FORMAT_NAME(XRGB_8888),
		FORMAT_NAME(BGRA_8888),
		FORMAT_NAME(BGRX_8888),
		FORMAT_NAME(Y_CBCR_H2V2_VENUS),
		FORMAT_NAME(Y_CBCR_H2V2),
		FORMAT_NAME(Y_CRCB_H2V2),
		FORMAT_NAME(Y_CB_CR_H2V2),
		FORMAT_NAME(Y_CR_CB_H2V2),
		FORMAT_NAME(Y_CR_CB_GH2V2),
		FORMAT_NAME(YCBYCR_H2V1),
		FORMAT_NAME(YCRYCB_H2V1),
#undef FORMAT_NAME
	};

	if (format >= ARRAY_SIZE(strings))
		return "UNKOWN";

	return strings[format];
}
void mdss_mdp_dump(struct mdss_data_type *mdata);

#ifdef CONFIG_DEBUG_FS
int mdss_mdp_debugfs_init(struct mdss_data_type *mdata);
#else
static inline int mdss_mdp_debugfs_init(struct mdss_data_type *mdata)
{
	return 0;
}
#endif

#endif /* MDSS_MDP_DEBUG_H */
Loading