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

Commit 9cb6c868 authored by Mayank Chopra's avatar Mayank Chopra
Browse files

msm: mdss: MISR based CRC validation



MISR allows a CRC to be generated from contents of a
particular hw block which can be used for validation.
Enable setup of misr and APIs to obtain CRC from hw blocks.

Change-Id: Ib07e31cba45d242922bd28b6b306220efece7b8d
Acked-by: default avatarSachin Bhayare <sbhayare@qti.qualcomm.com>
Signed-off-by: default avatarMayank Chopra <makchopra@codeaurora.org>
parent 34fffd47
Loading
Loading
Loading
Loading
+190 −44
Original line number Diff line number Diff line
@@ -23,12 +23,13 @@

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

#define DEFAULT_BASE_REG_CNT 0x100
#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;
@@ -409,28 +410,63 @@ int mdss_debugfs_remove(struct mdss_data_type *mdata)
	return 0;
}

int vsync_count;
static struct mdss_mdp_misr_map {
	u32 ctrl_reg;
	u32 value_reg;
	u32 crc_op_mode;
	u32 crc_index;
	u32 crc_value[MISR_CRC_BATCH_SIZE];
	bool use_ping;
	bool is_ping_full;
	bool is_pong_full;
	struct mutex crc_lock;
	u32 crc_ping[MISR_CRC_BATCH_SIZE];
	u32 crc_pong[MISR_CRC_BATCH_SIZE];
} mdss_mdp_misr_table[DISPLAY_MISR_MAX] = {
	[DISPLAY_MISR_DSI0] = {
		.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_DSI0,
		.value_reg = MDSS_MDP_LP_MISR_SIGN_DSI0,
		.crc_op_mode = 0,
		.crc_index = 0,
		.use_ping = true,
		.is_ping_full = false,
		.is_pong_full = false,
	},
	[DISPLAY_MISR_DSI1] = {
		.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_DSI1,
		.value_reg = MDSS_MDP_LP_MISR_SIGN_DSI1,
		.crc_op_mode = 0,
		.crc_index = 0,
		.use_ping = true,
		.is_ping_full = false,
		.is_pong_full = false,
	},
	[DISPLAY_MISR_EDP] = {
		.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_EDP,
		.value_reg = MDSS_MDP_LP_MISR_SIGN_EDP,
		.crc_op_mode = 0,
		.crc_index = 0,
		.use_ping = true,
		.is_ping_full = false,
		.is_pong_full = false,
	},
	[DISPLAY_MISR_HDMI] = {
		.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_HDMI,
		.value_reg = MDSS_MDP_LP_MISR_SIGN_HDMI,
		.crc_op_mode = 0,
		.crc_index = 0,
		.use_ping = true,
		.is_ping_full = false,
		.is_pong_full = false,
	},
	[DISPLAY_MISR_MDP] = {
		.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_MDP,
		.value_reg = MDSS_MDP_LP_MISR_SIGN_MDP,
		.crc_op_mode = 0,
		.crc_index = 0,
		.use_ping = true,
		.is_ping_full = false,
		.is_pong_full = false,
	},
};

@@ -438,7 +474,7 @@ static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id)
{
	struct mdss_mdp_misr_map *map;

	if (block_id > DISPLAY_MISR_LCDC) {
	if (block_id > DISPLAY_MISR_MDP) {
		pr_err("MISR Block id (%d) out of range\n", block_id);
		return NULL;
	}
@@ -452,23 +488,51 @@ static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id)
	return map;
}

int mdss_misr_crc_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)
{
	struct mdss_mdp_misr_map *map;
	u32 config = 0;

	struct mdss_mdp_mixer *mixer;
	u32 config = 0, val = 0;
	u32 mixer_num = 0;
	bool is_valid_wb_mixer = true;
	map = mdss_misr_get_map(req->block_id);
	if (!map) {
		pr_err("Invalid MISR Block=%d\n", req->block_id);
		return -EINVAL;
	}

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
	if (req->block_id == DISPLAY_MISR_MDP) {
		mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
		mixer_num = mixer->num;
		pr_debug("SET MDP MISR BLK to MDSS_MDP_LP_MISR_SEL_LMIX%d_GC\n",
			req->block_id);
		switch (mixer_num) {
		case MDSS_MDP_INTF_LAYERMIXER0:
			pr_debug("Use Layer Mixer 0 for WB CRC\n");
			val = MDSS_MDP_LP_MISR_SEL_LMIX0_GC;
			break;
		case MDSS_MDP_INTF_LAYERMIXER1:
			pr_debug("Use Layer Mixer 1 for WB CRC\n");
			val = MDSS_MDP_LP_MISR_SEL_LMIX1_GC;
			break;
		case MDSS_MDP_INTF_LAYERMIXER2:
			pr_debug("Use Layer Mixer 2 for WB CRC\n");
			val = MDSS_MDP_LP_MISR_SEL_LMIX2_GC;
			break;
		default:
			pr_err("Invalid Layer Mixer %d selected for WB CRC\n",
				mixer_num);
			is_valid_wb_mixer = false;
			break;
		}
		if (is_valid_wb_mixer)
			writel_relaxed(val,
				mdata->mdp_base + MDSS_MDP_LP_MISR_SEL);
	}
	vsync_count = 0;
	map->crc_op_mode = req->crc_op_mode;
	memset(map->crc_value, 0, sizeof(map->crc_value));

	pr_debug("MISR Config (BlockId %d) (Frame Count = %d)\n",
		req->block_id, req->frame_count);

	config = (MDSS_MDP_LP_MISR_CTRL_FRAME_COUNT_MASK & req->frame_count) |
			(MDSS_MDP_LP_MISR_CTRL_ENABLE);

@@ -476,24 +540,32 @@ int mdss_misr_crc_set(struct mdss_data_type *mdata, struct mdp_misr *req)
			mdata->mdp_base + map->ctrl_reg);
	/* ensure clear is done */
	wmb();
	if (MISR_OP_BM == map->crc_op_mode) {
		writel_relaxed(MISR_CRC_BATCH_CFG,
			mdata->mdp_base + map->ctrl_reg);
	} else {

	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;

	if (MISR_OP_BM != map->crc_op_mode) {

		writel_relaxed(config,
				mdata->mdp_base + map->ctrl_reg);

		config = readl_relaxed(mdata->mdp_base + map->ctrl_reg);
		pr_debug("MISR_CTRL = 0x%x", config);
		pr_debug("MISR_CTRL = 0x%x",
				readl_relaxed(mdata->mdp_base + map->ctrl_reg));
	}
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
	return 0;
}

int mdss_misr_crc_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)
{
	struct mdss_mdp_misr_map *map;
	u32 status;
	int ret = 0;
	int ret = -1;
	int i;

	map = mdss_misr_get_map(resp->block_id);
@@ -501,35 +573,60 @@ int mdss_misr_crc_get(struct mdss_data_type *mdata, struct mdp_misr *resp)
		pr_err("Invalid MISR Block=%d\n", resp->block_id);
		return -EINVAL;
	}

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
	switch (map->crc_op_mode) {
	case MISR_OP_SFM:
	case MISR_OP_MFM:
		ret = readl_poll_timeout(mdata->mdp_base + map->ctrl_reg,
				status, status & MDSS_MDP_LP_MISR_CTRL_STATUS,
				MISR_POLL_SLEEP, MISR_POLL_TIMEOUT);

		pr_debug("Status of Get MISR_CTRL = 0x%x", status);
		if (ret == 0) {
			resp->crc_value[0] =
				readl_relaxed(mdata->mdp_base + map->value_reg);
			resp->crc_value[0] = readl_relaxed(mdata->mdp_base +
				map->value_reg);
			pr_debug("CRC %d=0x%x\n", resp->block_id,
				resp->crc_value[0]);
			writel_relaxed(0, mdata->mdp_base + map->ctrl_reg);
		} else {
			pr_warn("MISR %d busy with status 0x%x\n",
					resp->block_id, status);
			mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
			ret = readl_poll_timeout(mdata->mdp_base +
					map->ctrl_reg, status,
					status & MDSS_MDP_LP_MISR_CTRL_STATUS,
					MISR_POLL_SLEEP, MISR_POLL_TIMEOUT);
			if (ret == 0) {
				resp->crc_value[0] =
					readl_relaxed(mdata->mdp_base +
					map->value_reg);
			}
			writel_relaxed(0, mdata->mdp_base + map->ctrl_reg);
		}
		break;
	case MISR_OP_BM:
		if (map->is_ping_full) {
			for (i = 0; i < MISR_CRC_BATCH_SIZE; i++)
			resp->crc_value[i] = map->crc_value[i];
		map->crc_index = 0;
				resp->crc_value[i] = map->crc_ping[i];
			memset(map->crc_ping, 0, sizeof(map->crc_ping));
			map->is_ping_full = false;
			ret = 0;
		} else if (map->is_pong_full) {
			for (i = 0; i < MISR_CRC_BATCH_SIZE; i++)
				resp->crc_value[i] = map->crc_pong[i];
			memset(map->crc_pong, 0, sizeof(map->crc_pong));
			map->is_pong_full = false;
			ret = 0;
		} else {
			pr_debug("mdss_mdp_misr_crc_get PING BUF %s\n",
				map->is_ping_full ? "FULL" : "EMPTRY");
			pr_debug("mdss_mdp_misr_crc_get PONG BUF %s\n",
				map->is_pong_full ? "FULL" : "EMPTRY");
		}
		resp->crc_op_mode = map->crc_op_mode;
		break;
	default:
		ret = -ENOSYS;
		break;
	}

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
	return ret;
}

@@ -537,22 +634,71 @@ int mdss_misr_crc_get(struct mdss_data_type *mdata, struct mdp_misr *resp)
void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id)
{
	struct mdss_mdp_misr_map *map;
	u32 status, config;
	u32 status = 0;
	u32 crc = 0x0BAD0BAD;
	bool crc_stored = false;

	map = mdss_misr_get_map(block_id);
	if (!map || (map->crc_op_mode != MISR_OP_BM))
		return;

	config = MISR_CRC_BATCH_CFG;

	status = readl_relaxed(mdata->mdp_base + map->ctrl_reg);
	if (status & MDSS_MDP_LP_MISR_CTRL_STATUS) {
		map->crc_value[map->crc_index] =
			readl_relaxed(mdata->mdp_base + map->value_reg);
		map->crc_index++;
		if (map->crc_index == MISR_CRC_BATCH_SIZE)
	if (MDSS_MDP_LP_MISR_CTRL_STATUS & status) {
		crc = readl_relaxed(mdata->mdp_base + map->value_reg);
		if (map->use_ping) {
			if (map->is_ping_full) {
				pr_err("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");
			} else {
				map->crc_pong[map->crc_index] = crc;
				crc_stored = true;
			}
		}

		if (crc_stored) {
			map->crc_index = (map->crc_index + 1);
			if (map->crc_index == MISR_CRC_BATCH_SIZE) {
				map->crc_index = 0;
		config |= MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR;
				if (true == map->use_ping) {
					map->is_ping_full = true;
					map->use_ping = false;
				} else {
					map->is_pong_full = true;
					map->use_ping = true;
				}
				pr_debug("USE BUFF %s\n", map->use_ping ?
					"PING" : "PONG");
				pr_debug("mdss_misr_crc_collect PING BUF %s\n",
					map->is_ping_full ? "FULL" : "EMPTRY");
				pr_debug("mdss_misr_crc_collect PONG BUF %s\n",
					map->is_pong_full ? "FULL" : "EMPTRY");
			}
		} else {
			pr_err("CRC(%d) Not saved\n", crc);
		}

		writel_relaxed(MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR,
				mdata->mdp_base + map->ctrl_reg);
		writel_relaxed(MISR_CRC_BATCH_CFG,
				mdata->mdp_base + map->ctrl_reg);
	} else if (0 == status) {
		writel_relaxed(MISR_CRC_BATCH_CFG,
				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);

	if (MAX_VSYNC_COUNT == vsync_count) {
		pr_err("RESET vsync_count(%d)\n", vsync_count);
		vsync_count = 0;
	} else {
		vsync_count += 1;
	}
	writel_relaxed(config, mdata->mdp_base + map->ctrl_reg);
}
+17 −12
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@

#define MISR_POLL_SLEEP		2000
#define MISR_POLL_TIMEOUT	32000
#define MISR_CRC_BATCH_SIZE		32
#define MISR_CRC_BATCH_CFG	0x101

#ifdef CONFIG_DEBUG_FS
@@ -26,8 +25,10 @@ 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,
				    size_t max_offset);
int mdss_misr_crc_set(struct mdss_data_type *mdata, struct mdp_misr *req);
int mdss_misr_crc_get(struct mdss_data_type *mdata, struct mdp_misr *resp);
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,
			struct mdss_mdp_ctl *ctl);
void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id);
#else
static inline int mdss_debugfs_init(struct mdss_data_type *mdata) { return 0; }
@@ -35,10 +36,14 @@ static inline int mdss_debugfs_remove(struct mdss_data_type *mdata)
{ return 0; }
static inline int mdss_debug_register_base(const char *name, void __iomem *base,
					size_t max_offset) { return 0; }
static inline int mdss_misr_crc_set(struct mdss_data_type *mdata,
		      struct mdp_misr *reg) { return 0; }
static inline int mdss_misr_crc_get(struct mdss_data_type *mdata,
		      struct mdp_misr *resp) { return 0; }
static inline int mdss_misr_set(struct mdss_data_type *mdata,
					struct mdp_misr *req,
					struct mdss_mdp_ctl *ctl)
{ return 0; }
static inline int mdss_misr_get(struct mdss_data_type *mdata,
					struct mdp_misr *resp,
					struct mdss_mdp_ctl *ctl)
{ return 0; }
static inline void mdss_misr_crc_collect(struct mdss_data_type *mdata,
						int block_id) { }
#endif
+8 −2
Original line number Diff line number Diff line
@@ -1963,7 +1963,10 @@ static int mdss_fb_set_metadata(struct msm_fb_data_type *mfd,
				struct msmfb_metadata *metadata)
{
	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
	int ret = 0;
	if (!ctl)
		return  -EPERM;
	switch (metadata->op) {
	case metadata_op_vic:
		if (mfd->panel_info)
@@ -1975,7 +1978,7 @@ static int mdss_fb_set_metadata(struct msm_fb_data_type *mfd,
	case metadata_op_crc:
		if (!mfd->panel_power_on)
			return -EPERM;
		ret = mdss_misr_crc_set(mdata, &metadata->data.misr_request);
		ret = mdss_misr_set(mdata, &metadata->data.misr_request, ctl);
		break;
	case metadata_op_wb_format:
		ret = mdss_mdp_wb_set_format(mfd,
@@ -2008,7 +2011,10 @@ static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
				struct msmfb_metadata *metadata)
{
	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
	int ret = 0;
	if (!ctl)
		return -EPERM;
	switch (metadata->op) {
	case metadata_op_frame_rate:
		metadata->data.panel_frame_rate =
@@ -2020,7 +2026,7 @@ static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
	case metadata_op_crc:
		if (!mfd->panel_power_on)
			return -EPERM;
		ret = mdss_misr_crc_get(mdata, &metadata->data.misr_request);
		ret = mdss_misr_get(mdata, &metadata->data.misr_request, ctl);
		break;
	case metadata_op_wb_format:
		ret = mdss_mdp_wb_get_format(mfd, &metadata->data.mixer_cfg);
+9 −3
Original line number Diff line number Diff line
@@ -201,14 +201,20 @@ irqreturn_t mdss_mdp_isr(int irq, void *ptr)
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_HDMI);
	}

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

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

	if (isr & MDSS_MDP_INTR_WB_2_DONE)
	if (isr & MDSS_MDP_INTR_WB_2_DONE) {
		mdss_mdp_intr_done(MDP_INTR_WB_2);
		mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP);
	}

mdp_isr_done:
	hist_isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_HIST_INTR_STATUS);
+3 −1
Original line number Diff line number Diff line
@@ -468,12 +468,14 @@ struct mdp_histogram {
	uint32_t *b;
};

#define MISR_CRC_BATCH_SIZE 32
enum {
	DISPLAY_MISR_EDP,
	DISPLAY_MISR_DSI0,
	DISPLAY_MISR_DSI1,
	DISPLAY_MISR_HDMI,
	DISPLAY_MISR_LCDC,
	DISPLAY_MISR_MDP,
	DISPLAY_MISR_ATV,
	DISPLAY_MISR_DSI_CMD,
	DISPLAY_MISR_MAX
@@ -491,7 +493,7 @@ struct mdp_misr {
	uint32_t block_id;
	uint32_t frame_count;
	uint32_t crc_op_mode;
	uint32_t crc_value[32];
	uint32_t crc_value[MISR_CRC_BATCH_SIZE];
};

/*