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

Commit 5ab7b2da authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mdss: add real time debug log"

parents 2e92e61e 50df4413
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@ mdss-mdp-objs += mdss_mdp_wb.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o

ifeq ($(CONFIG_FB_MSM_MDSS),y)
obj-$(CONFIG_DEBUG_FS) += mdss_debug.o
obj-$(CONFIG_DEBUG_FS) += mdss_debug.o mdss_debug_xlog.o
endif

dsi-v2-objs = dsi_v2.o dsi_host_v2.o dsi_io_v2.o
+31 −16
Original line number Diff line number Diff line
@@ -30,21 +30,6 @@
#define GROUP_BYTES 4
#define ROW_BYTES 16
#define MAX_VSYNC_COUNT 0xFFFFFFF
struct mdss_debug_data {
	struct dentry *root;
	struct list_head base_list;
};

struct mdss_debug_base {
	struct mdss_debug_data *mdd;
	void __iomem *base;
	size_t off;
	size_t cnt;
	size_t max_offset;
	char *buf;
	size_t buf_len;
	struct list_head head;
};

static int mdss_debug_base_open(struct inode *inode, struct file *file)
{
@@ -266,12 +251,14 @@ int mdss_debug_register_base(const char *name, void __iomem *base,
	if (!dbg)
		return -ENOMEM;

	if (name)
		strlcpy(dbg->name, name, sizeof(dbg->name));
	dbg->base = base;
	dbg->max_offset = max_offset;
	dbg->off = 0;
	dbg->cnt = DEFAULT_BASE_REG_CNT;

	if (name)
	if (name && strcmp(name, "mdp"))
		prefix_len = snprintf(dn, sizeof(dn), "%s_", name);

	strlcpy(dn + prefix_len, "off", sizeof(dn) - prefix_len);
@@ -396,6 +383,11 @@ int mdss_debugfs_init(struct mdss_data_type *mdata)
	debugfs_create_u32("min_mdp_clk", 0644, mdd->root,
			(u32 *)&mdata->min_mdp_clk);

	if (mdss_create_xlog_debug(mdd)) {
		mdss_debugfs_cleanup(mdd);
		return -ENODEV;
	}

	mdata->debug_inf.debug_data = mdd;

	return 0;
@@ -411,6 +403,29 @@ int mdss_debugfs_remove(struct mdss_data_type *mdata)
	return 0;
}

void mdss_dump_reg(char __iomem *base, int len)
{
	char *addr;
	u32 x0, x4, x8, xc;
	int i;

	addr = base;
	if (len % 16)
		len += 16;
	len /= 16;

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
	for (i = 0; i < len; i++) {
		x0 = readl_relaxed(addr+0x0);
		x4 = readl_relaxed(addr+0x4);
		x8 = readl_relaxed(addr+0x8);
		xc = readl_relaxed(addr+0xc);
		pr_info("%p : %08x %08x %08x %08x\n", addr, x0, x4, x8, xc);
		addr += 16;
	}
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
}

int vsync_count;
static struct mdss_mdp_misr_map {
	u32 ctrl_reg;
+50 −1
Original line number Diff line number Diff line
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-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
@@ -14,13 +14,48 @@
#ifndef MDSS_DEBUG_H
#define MDSS_DEBUG_H

#include <stdarg.h>
#include "mdss.h"

#define MISR_POLL_SLEEP		2000
#define MISR_POLL_TIMEOUT	32000
#define MISR_CRC_BATCH_CFG	0x101
#define DATA_LIMITER (-1)
#define XLOG_TOUT_DATA_LIMITER (NULL)
#define XLOG_FUNC_ENTRY	0x1111
#define XLOG_FUNC_EXIT	0x2222
#define MDSS_REG_BLOCK_NAME_LEN (5)

#define MDSS_XLOG(...) mdss_xlog(__func__, ##__VA_ARGS__, DATA_LIMITER)
#define MDSS_XLOG_TOUT_HANDLER(...)	\
	mdss_xlog_tout_handler(__func__, ##__VA_ARGS__, XLOG_TOUT_DATA_LIMITER)

#ifdef CONFIG_DEBUG_FS
struct mdss_debug_base {
	struct mdss_debug_data *mdd;
	char name[80];
	void __iomem *base;
	size_t off;
	size_t cnt;
	size_t max_offset;
	char *buf;
	size_t buf_len;
	struct list_head head;
};

struct debug_log {
	struct dentry *xlog;
	u32 xlog_enable;
	u32 panic_on_err;
	u32 enable_reg_dump;
};

struct mdss_debug_data {
	struct dentry *root;
	struct list_head base_list;
	struct debug_log logd;
};

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,
@@ -30,6 +65,13 @@ int mdss_misr_set(struct mdss_data_type *mdata, struct mdp_misr *req,
int mdss_misr_get(struct mdss_data_type *mdata, struct mdp_misr *resp,
			struct mdss_mdp_ctl *ctl);
void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id);

int mdss_create_xlog_debug(struct mdss_debug_data *mdd);
void mdss_xlog(const char *name, ...);
void mdss_xlog_dump(void);
void mdss_dump_reg(char __iomem *base, int len);
void mdss_dsi_debug_check_te(struct mdss_panel_data *pdata);
void mdss_xlog_tout_handler(const char *name, ...);
#else
static inline int mdss_debugfs_init(struct mdss_data_type *mdata) { return 0; }
static inline int mdss_debugfs_remove(struct mdss_data_type *mdata)
@@ -46,5 +88,12 @@ static inline int mdss_misr_get(struct mdss_data_type *mdata,
{ return 0; }
static inline void mdss_misr_crc_collect(struct mdss_data_type *mdata,
						int block_id) { }

static inline int create_xlog_debug(struct mdss_data_type *mdata) { }
static inline void mdss_xlog(const char *name, ...) { }
static inline void mdss_xlog_dump(void) { }
static inline void mdss_dump_reg(char __iomem *base, int len) { }
static inline void mdss_dsi_debug_check_te(struct mdss_panel_data *pdata) { }
static inline void mdss_xlog_tout_handler(const char *name, ...) { }
#endif
#endif /* MDSS_DEBUG_H */
+196 −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/delay.h>
#include <linux/spinlock.h>
#include <linux/ktime.h>
#include <linux/debugfs.h>

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

#define MDSS_XLOG_ENTRY	256
#define MDSS_XLOG_MAX_DATA 6
#define MDSS_XLOG_BUF_MAX 512

struct tlog {
	u32 tick;
	const char *name;
	u32 data[MDSS_XLOG_MAX_DATA];
	u32 data_cnt;
};

struct mdss_dbg_xlog {
	struct tlog logs[MDSS_XLOG_ENTRY];
	int first;
	int last;
	spinlock_t xlock;
} mdss_dbg_xlog;

static int mdss_xlog_dump_open(struct inode *inode, struct file *file)
{
	/* non-seekable */
	file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
	file->private_data = inode->i_private;
	return 0;
}

static ssize_t mdss_xlog_dump_read(struct file *file, char __user *buff,
		size_t count, loff_t *ppos)
{
	MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0", "dsi1", "edp", "hdmi", "panic");
	return 0;
}

static const struct file_operations mdss_xlog_fops = {
	.open = mdss_xlog_dump_open,
	.read = mdss_xlog_dump_read,
};

int mdss_create_xlog_debug(struct mdss_debug_data *mdd)
{
	spin_lock_init(&mdss_dbg_xlog.xlock);

	mdd->logd.xlog = debugfs_create_dir("xlog", mdd->root);
	if (IS_ERR_OR_NULL(mdd->logd.xlog)) {
		pr_err("debugfs_create_dir fail, error %ld\n",
		       PTR_ERR(mdd->logd.xlog));
		mdd->logd.xlog = NULL;
		return -ENODEV;
	}
	debugfs_create_file("dump", 0644, mdd->logd.xlog, NULL,
						&mdss_xlog_fops);
	debugfs_create_bool("enable", 0644, mdd->logd.xlog,
			    &mdd->logd.xlog_enable);
	debugfs_create_bool("panic", 0644, mdd->logd.xlog,
			    &mdd->logd.panic_on_err);
	debugfs_create_bool("reg_dump", 0644, mdd->logd.xlog,
			    &mdd->logd.enable_reg_dump);
	return 0;
}

void mdss_xlog(const char *name, ...)
{
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	struct mdss_debug_data *mdd = mdata->debug_inf.debug_data;
	unsigned long flags;
	int i, val = 0;
	va_list args;
	struct tlog *log;
	ktime_t time;

	if (!mdd->logd.xlog_enable)
		return;

	spin_lock_irqsave(&mdss_dbg_xlog.xlock, flags);

	time = ktime_get();

	log = &mdss_dbg_xlog.logs[mdss_dbg_xlog.first];
	log->tick = ktime_to_us(time);
	log->name = name;
	log->data_cnt = 0;

	va_start(args, name);
	for (i = 0; i < MDSS_XLOG_MAX_DATA; i++) {

		val = va_arg(args, int);
		if (val == DATA_LIMITER)
			break;

		log->data[i] = val;
	}
	va_end(args);

	log->data_cnt = i;

	mdss_dbg_xlog.last = mdss_dbg_xlog.first;
	mdss_dbg_xlog.first++;
	mdss_dbg_xlog.first %= MDSS_XLOG_ENTRY;

	spin_unlock_irqrestore(&mdss_dbg_xlog.xlock, flags);
}

void mdss_xlog_dump(void)
{
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	struct mdss_debug_data *mdd = mdata->debug_inf.debug_data;
	int i, n, d_cnt, off;
	unsigned long flags;
	struct tlog *log;
	char xlog_buf[MDSS_XLOG_BUF_MAX];

	if (!mdd->logd.xlog_enable)
		return;

	spin_lock_irqsave(&mdss_dbg_xlog.xlock, flags);
	i = mdss_dbg_xlog.first;
	for (n = 0; n < MDSS_XLOG_ENTRY; n++) {
		log = &mdss_dbg_xlog.logs[i];
		off = snprintf(xlog_buf, MDSS_XLOG_BUF_MAX, "%-32s => %08d: ",
							log->name, log->tick);
		for (d_cnt = 0; d_cnt < log->data_cnt;) {
			off += snprintf((xlog_buf + off),
					(MDSS_XLOG_BUF_MAX - off),
					"%x ", log->data[d_cnt]);
			d_cnt++;
		}
		pr_err("%s\n", xlog_buf);

		i = (i + 1) % MDSS_XLOG_ENTRY;
	}
	spin_unlock_irqrestore(&mdss_dbg_xlog.xlock, flags);
}

void mdss_xlog_tout_handler(const char *name, ...)
{
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	struct mdss_debug_data *mdd = mdata->debug_inf.debug_data;
	struct mdss_debug_base *blk_base, *tmp;
	int i, dead = 0;
	va_list args;
	char *blk_name = NULL;

	if (!mdd->logd.xlog_enable)
		return;

	va_start(args, name);
	for (i = 0; i < MDSS_XLOG_MAX_DATA; i++) {

		blk_name = va_arg(args, char*);
		if (IS_ERR_OR_NULL(blk_name))
			break;

		list_for_each_entry_safe(blk_base, tmp, &mdd->base_list, head) {

			if (blk_base->name &&
				!strcmp(blk_base->name, blk_name) &&
				mdd->logd.enable_reg_dump) {
				pr_info("\n%s  :   =========%s DUMP=========\n",
						__func__, blk_base->name);
				mdss_dump_reg(blk_base->base,
						blk_base->max_offset);
			}
		}
		if (!strcmp(blk_name, "panic"))
			dead = 1;
	}
	va_end(args);

	MDSS_XLOG(0xffff, 0xffff, 0xffff, 0xffff, 0xffff);
	mdss_xlog_dump();

	if (dead && mdd->logd.panic_on_err)
		panic(name);
}
+2 −0
Original line number Diff line number Diff line
@@ -1024,6 +1024,8 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
				panel_data);
	pr_debug("%s+:event=%d\n", __func__, event);

	MDSS_XLOG(event, arg, ctrl_pdata->ndx, 0x3333);

	switch (event) {
	case MDSS_EVENT_UNBLANK:
		rc = mdss_dsi_on(pdata);
Loading