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

Commit 8c7db62b 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 sysfs to generate the misr crc during interrupts"

parents 09f67dcc 8a353735
Loading
Loading
Loading
Loading
+105 −14
Original line number Diff line number Diff line
/* Copyright (c) 2009-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2009-2016, 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
@@ -1171,6 +1171,7 @@ static struct mdss_mdp_misr_map {
	u32 value_reg;
	u32 crc_op_mode;
	u32 crc_index;
	u32 last_misr;
	bool use_ping;
	bool is_ping_full;
	bool is_pong_full;
@@ -1183,6 +1184,7 @@ static struct mdss_mdp_misr_map {
		.value_reg = MDSS_MDP_LP_MISR_SIGN_DSI0,
		.crc_op_mode = 0,
		.crc_index = 0,
		.last_misr = 0,
		.use_ping = true,
		.is_ping_full = false,
		.is_pong_full = false,
@@ -1192,6 +1194,7 @@ static struct mdss_mdp_misr_map {
		.value_reg = MDSS_MDP_LP_MISR_SIGN_DSI1,
		.crc_op_mode = 0,
		.crc_index = 0,
		.last_misr = 0,
		.use_ping = true,
		.is_ping_full = false,
		.is_pong_full = false,
@@ -1201,6 +1204,7 @@ static struct mdss_mdp_misr_map {
		.value_reg = MDSS_MDP_LP_MISR_SIGN_EDP,
		.crc_op_mode = 0,
		.crc_index = 0,
		.last_misr = 0,
		.use_ping = true,
		.is_ping_full = false,
		.is_pong_full = false,
@@ -1210,6 +1214,7 @@ static struct mdss_mdp_misr_map {
		.value_reg = MDSS_MDP_LP_MISR_SIGN_HDMI,
		.crc_op_mode = 0,
		.crc_index = 0,
		.last_misr = 0,
		.use_ping = true,
		.is_ping_full = false,
		.is_pong_full = false,
@@ -1219,6 +1224,7 @@ static struct mdss_mdp_misr_map {
		.value_reg = MDSS_MDP_LP_MISR_SIGN_MDP,
		.crc_op_mode = 0,
		.crc_index = 0,
		.last_misr = 0,
		.use_ping = true,
		.is_ping_full = false,
		.is_pong_full = false,
@@ -1226,7 +1232,8 @@ static struct mdss_mdp_misr_map {
};

static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id,
		struct mdss_mdp_ctl *ctl, struct mdss_data_type *mdata)
		struct mdss_mdp_ctl *ctl, struct mdss_data_type *mdata,
		bool is_video_mode)
{
	struct mdss_mdp_misr_map *map;
	struct mdss_mdp_mixer *mixer;
@@ -1259,11 +1266,23 @@ static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id,

				if ((block_id == DISPLAY_MISR_DSI0 ||
				     block_id == DISPLAY_MISR_DSI1) &&
				     (ctl && !ctl->is_video_mode)) {
				     !is_video_mode) {
					ctrl_reg = intf_base +
						MDSS_MDP_INTF_CMD_MISR_CTRL;
					value_reg = intf_base +
					    MDSS_MDP_INTF_CMD_MISR_SIGNATURE;

					/*
					 * extra offset required for
					 * cmd misr in 8996
					 */
					if (IS_MDSS_MAJOR_MINOR_SAME(
						  mdata->mdp_rev,
						  MDSS_MDP_HW_REV_107)) {
						ctrl_reg += 0x8;
						value_reg += 0x8;
					}

				} else {
					ctrl_reg = intf_base +
						MDSS_MDP_INTF_MISR_CTRL;
@@ -1325,6 +1344,33 @@ static bool switch_mdp_misr_offset(struct mdss_mdp_misr_map *map, u32 mdp_rev,
	return use_mdp_up_misr;
}

void mdss_misr_disable(struct mdss_data_type *mdata,
			struct mdp_misr *req,
			struct mdss_mdp_ctl *ctl)
{
	struct mdss_mdp_misr_map *map;

	map = mdss_misr_get_map(req->block_id, ctl, mdata,
		ctl->is_video_mode);

	/* clear the map data */
	memset(map->crc_ping, 0, sizeof(map->crc_ping));
	memset(map->crc_pong, 0, sizeof(map->crc_pong));
	map->crc_index = 0;
	map->use_ping = true;
	map->is_ping_full = false;
	map->is_pong_full = false;
	map->crc_op_mode = 0;
	map->last_misr = 0;

	/* disable MISR and clear the status */
	writel_relaxed(MDSS_MDP_MISR_CTRL_STATUS_CLEAR,
			mdata->mdp_base + map->ctrl_reg);

	/* make sure status is clear */
	wmb();
}

int mdss_misr_set(struct mdss_data_type *mdata,
			struct mdp_misr *req,
			struct mdss_mdp_ctl *ctl)
@@ -1336,7 +1382,11 @@ int mdss_misr_set(struct mdss_data_type *mdata,
	bool is_valid_wb_mixer = true;
	bool use_mdp_up_misr = false;

	map = mdss_misr_get_map(req->block_id, ctl, mdata);
	pr_debug("req[block:%d frame:%d op_mode:%d]\n",
		req->block_id, req->frame_count, req->crc_op_mode);

	map = mdss_misr_get_map(req->block_id, ctl, mdata,
		ctl->is_video_mode);

	if (!map) {
		pr_err("Invalid MISR Block=%d\n", req->block_id);
@@ -1409,8 +1459,9 @@ int mdss_misr_set(struct mdss_data_type *mdata,

		writel_relaxed(config,
				mdata->mdp_base + map->ctrl_reg);
		pr_debug("MISR_CTRL = 0x%x",
				readl_relaxed(mdata->mdp_base + map->ctrl_reg));
		pr_debug("MISR_CTRL=0x%x [base:0x%p reg:0x%x config:0x%x]\n",
				readl_relaxed(mdata->mdp_base + map->ctrl_reg),
				mdata->mdp_base, map->ctrl_reg, config);
	}
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
	return 0;
@@ -1431,7 +1482,8 @@ char *get_misr_block_name(int misr_block_id)

int mdss_misr_get(struct mdss_data_type *mdata,
			struct mdp_misr *resp,
			struct mdss_mdp_ctl *ctl)
			struct mdss_mdp_ctl *ctl,
			bool is_video_mode)
{
	struct mdss_mdp_misr_map *map;
	struct mdss_mdp_mixer *mixer;
@@ -1439,7 +1491,11 @@ int mdss_misr_get(struct mdss_data_type *mdata,
	int ret = -1;
	int i;

	map = mdss_misr_get_map(resp->block_id, ctl, mdata);
	pr_debug("req[block:%d frame:%d op_mode:%d]\n",
		resp->block_id, resp->frame_count, resp->crc_op_mode);

	map = mdss_misr_get_map(resp->block_id, ctl, mdata,
		is_video_mode);
	if (!map) {
		pr_err("Invalid MISR Block=%d\n", resp->block_id);
		return -EINVAL;
@@ -1515,31 +1571,37 @@ int mdss_misr_get(struct mdss_data_type *mdata,
}

/* This function is expected to be called from interrupt context */
void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id)
void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id,
	bool is_video_mode)
{
	struct mdss_mdp_misr_map *map;
	u32 status = 0;
	u32 crc = 0x0BAD0BAD;
	bool crc_stored = false;

	map = mdss_misr_get_map(block_id, NULL, mdata);
	map = mdss_misr_get_map(block_id, NULL, mdata, is_video_mode);
	if (!map || (map->crc_op_mode != MISR_OP_BM))
		return;

	switch_mdp_misr_offset(map, mdata->mdp_rev, block_id);

	status = readl_relaxed(mdata->mdp_base + map->ctrl_reg);

	if (MDSS_MDP_MISR_CTRL_STATUS & status) {

		crc = readl_relaxed(mdata->mdp_base + map->value_reg);
		map->last_misr = crc; /* cache crc to get it from sysfs */

		if (map->use_ping) {
			if (map->is_ping_full) {
				pr_err("PING Buffer FULL\n");
				pr_err_once("PING Buffer FULL\n");
			} else {
				map->crc_ping[map->crc_index] = crc;
				crc_stored = true;
			}
		} else {
			if (map->is_pong_full) {
				pr_err("PONG Buffer FULL\n");
				pr_err_once("PONG Buffer FULL\n");
			} else {
				map->crc_pong[map->crc_index] = crc;
				crc_stored = true;
@@ -1565,7 +1627,7 @@ void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id)
					map->is_pong_full ? "FULL" : "EMPTRY");
			}
		} else {
			pr_err("CRC(%d) Not saved\n", crc);
			pr_err_once("CRC(%d) Not saved\n", crc);
		}

		if (mdata->mdp_rev < MDSS_MDP_HW_REV_105) {
@@ -1574,7 +1636,9 @@ void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id)
			writel_relaxed(MISR_CRC_BATCH_CFG,
				mdata->mdp_base + map->ctrl_reg);
		}

	} else if (0 == status) {

		if (mdata->mdp_rev < MDSS_MDP_HW_REV_105)
			writel_relaxed(MISR_CRC_BATCH_CFG,
					mdata->mdp_base + map->ctrl_reg);
@@ -1582,15 +1646,42 @@ void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id)
			writel_relaxed(MISR_CRC_BATCH_CFG |
					MDSS_MDP_LP_MISR_CTRL_FREE_RUN_MASK,
					mdata->mdp_base + map->ctrl_reg);

		pr_debug("$$ Batch CRC Start $$\n");
	}

	pr_debug("$$ Vsync Count = %d, CRC=0x%x Indx = %d$$\n",
		vsync_count, crc, map->crc_index);
	trace_mdp_misr_crc(block_id, vsync_count, crc);

	if (MAX_VSYNC_COUNT == vsync_count) {
		pr_err("RESET vsync_count(%d)\n", vsync_count);
		pr_debug("RESET vsync_count(%d)\n", vsync_count);
		vsync_count = 0;
	} else {
		vsync_count += 1;
	}

}

int mdss_dump_misr_data(char **buf, u32 size)
{
	struct mdss_mdp_misr_map  *dsi0_map;
	struct mdss_mdp_misr_map  *dsi1_map;
	struct mdss_mdp_misr_map  *hdmi_map;
	int ret;

	dsi0_map = &mdss_mdp_misr_table[DISPLAY_MISR_DSI0];
	dsi1_map = &mdss_mdp_misr_table[DISPLAY_MISR_DSI1];
	hdmi_map = &mdss_mdp_misr_table[DISPLAY_MISR_HDMI];

	ret = scnprintf(*buf, PAGE_SIZE,
			"\tDSI0 mode:%02d MISR:0x%08x\n"
			"\tDSI1 mode:%02d MISR:0x%08x\n"
			"\tHDMI mode:%02d MISR:0x%08x\n",
			dsi0_map->crc_op_mode, dsi0_map->last_misr,
			dsi1_map->crc_op_mode, dsi1_map->last_misr,
			hdmi_map->crc_op_mode, hdmi_map->last_misr
			);

	return ret;
}
+21 −6
Original line number Diff line number Diff line
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2016, 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
@@ -146,11 +146,18 @@ void mdss_debug_register_dump_range(struct platform_device *pdev,
	const char *name_prop);
int panel_debug_register_base(const char *name, void __iomem *base,
				    size_t max_offset);
int mdss_misr_set(struct mdss_data_type *mdata, struct mdp_misr *req,
int mdss_misr_set(struct mdss_data_type *mdata,
			struct mdp_misr *req,
			struct mdss_mdp_ctl *ctl);
int mdss_misr_get(struct mdss_data_type *mdata, struct mdp_misr *resp,
int mdss_misr_get(struct mdss_data_type *mdata,
			struct mdp_misr *resp,
			struct mdss_mdp_ctl *ctl,
			bool is_video_mode);
void mdss_misr_disable(struct mdss_data_type *mdata,
			struct mdp_misr *req,
			struct mdss_mdp_ctl *ctl);
void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id);
void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id,
	bool is_video_mode);

int mdss_create_xlog_debug(struct mdss_debug_data *mdd);
void mdss_xlog(const char *name, int line, int flag, ...);
@@ -178,10 +185,16 @@ static inline int mdss_misr_set(struct mdss_data_type *mdata,
{ return 0; }
static inline int mdss_misr_get(struct mdss_data_type *mdata,
					struct mdp_misr *resp,
					struct mdss_mdp_ctl *ctl)
					struct mdss_mdp_ctl *ctl,
					bool is_video_mode)
{ return 0; }
static inline void mdss_misr_disable(struct mdss_data_type *mdata,
					struct mdp_misr *req,
					struct mdss_mdp_ctl *ctl)
{ return; }

static inline void mdss_misr_crc_collect(struct mdss_data_type *mdata,
						int block_id) { }
					int block_id, bool is_video_mode) { }

static inline int create_xlog_debug(struct mdss_data_type *mdata) { return 0; }
static inline void mdss_xlog_dump(void) { }
@@ -192,6 +205,8 @@ static inline void mdss_xlog_tout_handler_default(bool queue,
	const char *name, ...) { }
#endif

int mdss_dump_misr_data(char **buf, u32 size);

static inline int mdss_debug_register_io(const char *name,
		struct dss_io_data *io_data, struct mdss_debug_base **dbg_blk)
{
+103 −1
Original line number Diff line number Diff line
@@ -3114,6 +3114,106 @@ static ssize_t mdss_mdp_cmd_autorefresh_store(struct device *dev,
}


/* Print the last CRC Value read for batch mode */
static ssize_t mdss_mdp_misr_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	ssize_t ret = 0;
	struct fb_info *fbi = dev_get_drvdata(dev);
	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
	struct mdss_mdp_ctl *ctl;

	if (!mfd) {
		pr_err("Invalid mfd structure\n");
		return -EINVAL;
	}

	ctl = mfd_to_ctl(mfd);
	if (!ctl) {
		pr_err("Invalid ctl structure\n");
		return -EINVAL;
	}

	ret = mdss_dump_misr_data(&buf, PAGE_SIZE);

	return ret;
}

/*
 * Enable crc batch mode. By enabling this mode through sysfs
 * driver will keep collecting the misr in ftrace during interrupts,
 * until disabled.
 */
static ssize_t mdss_mdp_misr_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t len)
{
	int enable_misr, rc;
	struct fb_info *fbi = dev_get_drvdata(dev);
	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	struct mdss_mdp_ctl *ctl;
	struct mdp_misr req, sreq;

	if (!mfd) {
		pr_err("Invalid mfd structure\n");
		rc = -EINVAL;
		return rc;
	}

	ctl = mfd_to_ctl(mfd);
	if (!ctl) {
		pr_err("Invalid ctl structure\n");
		rc = -EINVAL;
		return rc;
	}

	rc = kstrtoint(buf, 10, &enable_misr);
	if (rc) {
		pr_err("kstrtoint failed. rc=%d\n", rc);
		return rc;
	}

	pr_debug("intf_type:%d enable:%d\n", ctl->intf_type, enable_misr);
	if (ctl->intf_type == MDSS_INTF_DSI) {

		req.block_id = DISPLAY_MISR_DSI0;
		req.crc_op_mode = MISR_OP_BM;
		req.frame_count = 1;
		if (is_panel_split(mfd)) {

			sreq.block_id = DISPLAY_MISR_DSI1;
			sreq.crc_op_mode = MISR_OP_BM;
			sreq.frame_count = 1;
		}
	} else if (ctl->intf_type == MDSS_INTF_HDMI) {

		req.block_id = DISPLAY_MISR_HDMI;
		req.crc_op_mode = MISR_OP_BM;
		req.frame_count = 1;
	} else {
		pr_err("misr not supported fo this fb:%d\n", mfd->index);
	}

	if (enable_misr) {
		mdss_misr_set(mdata, &req , ctl);

		if (is_panel_split(mfd))
			mdss_misr_set(mdata, &sreq , ctl);

	} else {
		mdss_misr_disable(mdata, &req, ctl);

		if (is_panel_split(mfd))
			mdss_misr_disable(mdata, &sreq , ctl);
	}

	pr_debug("misr %s\n", enable_misr ? "enabled" : "disabled");

	return len;
}

static DEVICE_ATTR(msm_misr_en, S_IRUGO | S_IWUSR,
	mdss_mdp_misr_show, mdss_mdp_misr_store);
static DEVICE_ATTR(msm_cmd_autorefresh_en, S_IRUGO | S_IWUSR,
	mdss_mdp_cmd_autorefresh_show, mdss_mdp_cmd_autorefresh_store);
static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL);
@@ -3130,6 +3230,7 @@ static struct attribute *mdp_overlay_sysfs_attrs[] = {
	&dev_attr_vsync_event.attr,
	&dev_attr_ad.attr,
	&dev_attr_dyn_pu.attr,
	&dev_attr_msm_misr_en.attr,
	&dev_attr_msm_cmd_autorefresh_en.attr,
	&dev_attr_hist_event.attr,
	&dev_attr_bl_event.attr,
@@ -3954,7 +4055,8 @@ static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
		ctl = mfd_to_ctl(mfd);
		if (!ctl || mdss_fb_is_power_off(mfd))
			return -EPERM;
		ret = mdss_misr_get(mdata, &metadata->data.misr_request, ctl);
		ret = mdss_misr_get(mdata, &metadata->data.misr_request, ctl,
			ctl->is_video_mode);
		break;
	default:
		pr_warn("Unsupported request to MDP META IOCTL.\n");
+18 −1
Original line number Diff line number Diff line
/*
 * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
 * Copyright (c) 2014-2016, 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
@@ -295,6 +295,23 @@ TRACE_EVENT(mdp_perf_update_bus,
			__entry->ib_quota)
);

TRACE_EVENT(mdp_misr_crc,
	TP_PROTO(u32 block_id, u32 vsync_cnt, u32 crc),
	TP_ARGS(block_id, vsync_cnt, crc),
	TP_STRUCT__entry(
			__field(u32, block_id)
			__field(u32, vsync_cnt)
			__field(u32, crc)
	),
	TP_fast_assign(
			__entry->block_id = block_id;
			__entry->vsync_cnt = vsync_cnt;
			__entry->crc = crc;
	),
	TP_printk("block_id:%d vsync_cnt:%d crc:0x%08x",
			__entry->block_id, __entry->vsync_cnt, __entry->crc)
);

TRACE_EVENT(mdp_cmd_pingpong_done,
	TP_PROTO(struct mdss_mdp_ctl *ctl, u32 pp_num, int koff_cnt),
	TP_ARGS(ctl, pp_num, koff_cnt),
+13 −9
Original line number Diff line number Diff line
@@ -188,11 +188,15 @@ irqreturn_t mdss_mdp_isr(int irq, void *ptr)
	if (isr & MDSS_MDP_INTR_INTF_3_UNDERRUN)
		mdss_mdp_intr_done(MDP_INTR_UNDERRUN_INTF_3);

	if (isr & MDSS_MDP_INTR_PING_PONG_0_DONE)
	if (isr & MDSS_MDP_INTR_PING_PONG_0_DONE) {
		mdss_mdp_intr_done(MDP_INTR_PING_PONG_0);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI0, false);
	}

	if (isr & MDSS_MDP_INTR_PING_PONG_1_DONE)
	if (isr & MDSS_MDP_INTR_PING_PONG_1_DONE) {
		mdss_mdp_intr_done(MDP_INTR_PING_PONG_1);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI1, false);
	}

	if (isr & MDSS_MDP_INTR_PING_PONG_2_DONE)
		mdss_mdp_intr_done(MDP_INTR_PING_PONG_2);
@@ -214,38 +218,38 @@ irqreturn_t mdss_mdp_isr(int irq, void *ptr)

	if (isr & MDSS_MDP_INTR_INTF_0_VSYNC) {
		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_EDP);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_EDP, true);
	}

	if (isr & MDSS_MDP_INTR_INTF_1_VSYNC) {
		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_1);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI0);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI0, true);
	}

	if (isr & MDSS_MDP_INTR_INTF_2_VSYNC) {
		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_2);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI1);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI1, true);
	}

	if (isr & MDSS_MDP_INTR_INTF_3_VSYNC) {
		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_3);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_HDMI);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_HDMI, true);
	}

	if (isr & MDSS_MDP_INTR_WB_0_DONE) {
		mdss_mdp_intr_done(MDP_INTR_WB_0);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP, true);
	}

	if (isr & MDSS_MDP_INTR_WB_1_DONE) {
		mdss_mdp_intr_done(MDP_INTR_WB_1);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP, true);
	}

	if (isr & ((mdata->mdp_rev == MDSS_MDP_HW_REV_108) ?
		MDSS_MDP_INTR_WB_2_DONE >> 2 : MDSS_MDP_INTR_WB_2_DONE)) {
		mdss_mdp_intr_done(MDP_INTR_WB_2);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP, true);
	}

	if (isr & MDSS_MDP_INTR_PING_PONG_0_AUTOREFRESH_DONE)