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

Commit 1d0805a9 authored by Adrian Salido-Moreno's avatar Adrian Salido-Moreno
Browse files

msm: mdss: add support for multi-rect feature



Add support for DMA multirect pipes available in new MDP revision.
These pipes are able to fetch two different buffers and rectangles to
allow more layers to be fetched. Add support and proper validation
checks for limitations.

CRs-Fixed: 987777
Change-Id: I588ecd7829a45908241f6d9fa1e97147e79798f6
Signed-off-by: default avatarUjwal Patel <ujwalp@codeaurora.org>
Signed-off-by: default avatarAdrian Salido-Moreno <adrianm@codeaurora.org>
parent 4ce12b32
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -162,6 +162,7 @@ enum mdss_hw_quirk {
	MDSS_QUIRK_MIN_BUS_VOTE,
	MDSS_QUIRK_FMT_PACK_PATTERN,
	MDSS_QUIRK_NEED_SECURE_MAP,
	MDSS_QUIRK_SRC_SPLIT_ALWAYS,
	MDSS_QUIRK_MAX,
};

@@ -187,6 +188,15 @@ enum mdss_qos_settings {
	MDSS_QOS_MAX,
};

enum mdss_mdp_pipe_type {
	MDSS_MDP_PIPE_TYPE_INVALID = -1,
	MDSS_MDP_PIPE_TYPE_VIG = 0,
	MDSS_MDP_PIPE_TYPE_RGB,
	MDSS_MDP_PIPE_TYPE_DMA,
	MDSS_MDP_PIPE_TYPE_CURSOR,
	MDSS_MDP_PIPE_TYPE_MAX,
};

struct reg_bus_client {
	char name[MAX_CLIENT_NAME_LEN];
	short usecase_ndx;
@@ -389,6 +399,7 @@ struct mdss_data_type {

	struct mdss_hw_settings *hw_settings;

	int rects_per_sspp[MDSS_MDP_PIPE_TYPE_MAX];
	struct mdss_mdp_pipe *vig_pipes;
	struct mdss_mdp_pipe *rgb_pipes;
	struct mdss_mdp_pipe *dma_pipes;
+15 −6
Original line number Diff line number Diff line
@@ -1520,6 +1520,8 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
		mdata->min_prefill_lines = 21;
		mdata->has_ubwc = true;
		mdata->pixel_ram_size = 50 * 1024;
		mdata->rects_per_sspp[MDSS_MDP_PIPE_TYPE_DMA] = 2;

		set_bit(MDSS_QOS_PER_PIPE_IB, mdata->mdss_qos_map);
		set_bit(MDSS_QOS_OVERHEAD_FACTOR, mdata->mdss_qos_map);
		set_bit(MDSS_QOS_CDP, mdata->mdss_qos_map);
@@ -1536,6 +1538,7 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
		mdss_mdp_init_default_prefill_factors(mdata);
		mdss_set_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU);
		mdss_set_quirk(mdata, MDSS_QUIRK_DSC_2SLICE_PU_THRPUT);
		mdss_set_quirk(mdata, MDSS_QUIRK_SRC_SPLIT_ALWAYS);
		mdata->has_wb_ubwc = true;
		set_bit(MDSS_CAPS_10_BIT_SUPPORTED, mdata->mdss_caps_map);
		break;
@@ -1899,14 +1902,14 @@ static void __update_sspp_info(struct mdss_mdp_pipe *pipe,
		(*cnt += scnprintf(buf + *cnt, len - *cnt, fmt, ##__VA_ARGS__))

	for (i = 0; i < pipe_cnt; i++) {
		SPRINT("pipe_num:%d pipe_type:%s pipe_ndx:%d pipe_is_handoff:%d display_id:%d ",
			pipe->num, type, pipe->ndx, pipe->is_handed_off,
			mdss_mdp_get_display_id(pipe));
		SPRINT("pipe_num:%d pipe_type:%s pipe_ndx:%d rects:%d pipe_is_handoff:%d display_id:%d ",
			pipe->num, type, pipe->ndx, pipe->multirect.max_rects,
			pipe->is_handed_off, mdss_mdp_get_display_id(pipe));
		SPRINT("fmts_supported:");
		for (j = 0; j < num_bytes && pipe; j++)
			SPRINT("%d,", pipe->supported_formats[j]);
		SPRINT("\n");
		pipe++;
		pipe += pipe->multirect.max_rects;
	}
#undef SPRINT
}
@@ -2648,6 +2651,7 @@ static int mdss_mdp_parse_dt_pipe_helper(struct platform_device *pdev,
	struct mdss_mdp_pipe *pipe_list;
	char prop_name[64];
	int i, cnt, rc;
	u32 rects_per_sspp;

	if (!out_plist)
		return -EINVAL;
@@ -2668,8 +2672,12 @@ static int mdss_mdp_parse_dt_pipe_helper(struct platform_device *pdev,
		return 0;
	}

	/* by default works in single rect mode unless otherwise noted */
	rects_per_sspp = mdata->rects_per_sspp[ptype] ? : 1;

	pipe_list = devm_kzalloc(&pdev->dev,
			(sizeof(struct mdss_mdp_pipe) * cnt), GFP_KERNEL);
			(sizeof(struct mdss_mdp_pipe) * cnt * rects_per_sspp),
			GFP_KERNEL);
	if (!pipe_list)
		return -ENOMEM;

@@ -2698,7 +2706,8 @@ static int mdss_mdp_parse_dt_pipe_helper(struct platform_device *pdev,
		goto parse_fail;

	rc = mdss_mdp_pipe_addr_setup(mdata, pipe_list, offsets, ftch_id,
			xin_id, ptype, pnums, cnt, priority_base);
			xin_id, ptype, pnums, cnt, rects_per_sspp,
			priority_base);
	if (rc)
		goto parse_fail;

+45 −13
Original line number Diff line number Diff line
@@ -114,14 +114,6 @@ enum mdss_mdp_mixer_mux {
	MDSS_MDP_MIXER_MUX_RIGHT,
};

enum mdss_mdp_pipe_type {
	MDSS_MDP_PIPE_TYPE_INVALID,
	MDSS_MDP_PIPE_TYPE_VIG,
	MDSS_MDP_PIPE_TYPE_RGB,
	MDSS_MDP_PIPE_TYPE_DMA,
	MDSS_MDP_PIPE_TYPE_CURSOR,
};

static inline enum mdss_mdp_sspp_index get_pipe_num_from_ndx(u32 ndx)
{
	u32 id;
@@ -647,6 +639,42 @@ struct mdss_mdp_shared_reg_ctrl {
	u32 bit_off;
};

enum mdss_mdp_pipe_rect {
	MDSS_MDP_PIPE_RECT0, /* default */
	MDSS_MDP_PIPE_RECT1,
	MDSS_MDP_PIPE_MAX_RECTS,
};

/**
 * enum mdss_mdp_pipe_multirect_mode - pipe multirect mode
 * @MDSS_MDP_PIPE_MULTIRECT_NONE:	pipe is not working in multirect mode
 * @MDSS_MDP_PIPE_MULTIRECT_PARALLEL:	rectangles are being fetched at the
 *					same time in time multiplexed fashion
 * @MDSS_MDP_PIPE_MULTIRECT_SERIAL:	rectangles are fetched serially, where
 *					one is only fetched after the other one
 *					is complete
 */
enum mdss_mdp_pipe_multirect_mode {
	MDSS_MDP_PIPE_MULTIRECT_NONE,
	MDSS_MDP_PIPE_MULTIRECT_PARALLEL,
	MDSS_MDP_PIPE_MULTIRECT_SERIAL,
};

/**
 * struct mdss_mdp_pipe_multirect_params - multirect info for layer or pipe
 * @num:	rectangle being operated, default is RECT0 if pipe doesn't
 *		support multirect
 * @mode:	mode of multirect operation, default is NONE
 * @next:	pointer to sibling pipe/layer which is also operating in
 *		multirect mode
 */
struct mdss_mdp_pipe_multirect_params {
	enum mdss_mdp_pipe_rect num; /* RECT0 or RECT1 */
	int max_rects;
	enum mdss_mdp_pipe_multirect_mode mode;
	void *next; /* pointer to next pipe or layer */
};

struct mdss_mdp_pipe {
	u32 num;
	u32 type;
@@ -719,6 +747,8 @@ struct mdss_mdp_pipe {
	u32 frame_rate;
	u8 csc_coeff_set;
	u8 supported_formats[BITS_TO_BYTES(MDP_IMGTYPE_LIMIT1)];

	struct mdss_mdp_pipe_multirect_params multirect;
};

struct mdss_mdp_writeback_arg {
@@ -1402,7 +1432,8 @@ int mdp_pipe_tune_perf(struct mdss_mdp_pipe *pipe,
	u32 flags);
int mdss_mdp_overlay_setup_scaling(struct mdss_mdp_pipe *pipe);
struct mdss_mdp_pipe *mdss_mdp_pipe_assign(struct mdss_data_type *mdata,
	struct mdss_mdp_mixer *mixer, u32 ndx);
	struct mdss_mdp_mixer *mixer, u32 ndx,
	enum mdss_mdp_pipe_rect rect_num);
struct mdss_mdp_pipe *mdss_mdp_overlay_pipe_reuse(
	struct msm_fb_data_type *mfd, int pipe_ndx);
void mdss_mdp_pipe_position_update(struct mdss_mdp_pipe *pipe,
@@ -1556,12 +1587,12 @@ int mdss_mdp_pipe_handoff(struct mdss_mdp_pipe *pipe);
int mdss_mdp_smp_handoff(struct mdss_data_type *mdata);
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(struct mdss_mdp_mixer *mixer,
	u32 type, struct mdss_mdp_pipe *left_blend_pipe);
struct mdss_mdp_pipe *mdss_mdp_pipe_get(struct mdss_data_type *mdata, u32 ndx);
struct mdss_mdp_pipe *mdss_mdp_pipe_get(u32 ndx,
	enum mdss_mdp_pipe_rect rect_num);
struct mdss_mdp_pipe *mdss_mdp_pipe_search(struct mdss_data_type *mdata,
						  u32 ndx);
	u32 ndx, enum mdss_mdp_pipe_rect rect_num);
int mdss_mdp_pipe_map(struct mdss_mdp_pipe *pipe);
void mdss_mdp_pipe_unmap(struct mdss_mdp_pipe *pipe);
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_dma(struct mdss_mdp_mixer *mixer);

u32 mdss_mdp_smp_calc_num_blocks(struct mdss_mdp_pipe *pipe);
u32 mdss_mdp_smp_get_size(struct mdss_mdp_pipe *pipe);
@@ -1571,7 +1602,8 @@ void mdss_mdp_smp_release(struct mdss_mdp_pipe *pipe);

int mdss_mdp_pipe_addr_setup(struct mdss_data_type *mdata,
	struct mdss_mdp_pipe *head, u32 *offsets, u32 *ftch_id, u32 *xin_id,
	u32 type, const int *pnums, u32 len, u8 priority_base);
	u32 type, const int *pnums, u32 len, u32 rects_per_sspp,
	u8 priority_base);
int mdss_mdp_mixer_addr_setup(struct mdss_data_type *mdata, u32 *mixer_offsets,
		u32 *dspp_offsets, u32 *pingpong_offsets, u32 type, u32 len);
int mdss_mdp_ctl_addr_setup(struct mdss_data_type *mdata, u32 *ctl_offsets,
+42 −17
Original line number Diff line number Diff line
@@ -57,6 +57,15 @@ static struct {
	[MDSS_MDP_SSPP_CURSOR1] = { 23, .ext  = { 26, 4, 0 } },
};

static struct {
	struct mdss_mdp_hwio_cfg ext2;
} mdp_pipe_rec1_hwio[MDSS_MDP_MAX_SSPP] = {
	[MDSS_MDP_SSPP_DMA0]    = { .ext2 = {  8, 4, 0 } },
	[MDSS_MDP_SSPP_DMA1]    = { .ext2 = { 12, 4, 0 } },
	[MDSS_MDP_SSPP_DMA2]    = { .ext2 = { 16, 4, 0 } },
	[MDSS_MDP_SSPP_DMA3]    = { .ext2 = { 20, 4, 0 } },
};

static void __mdss_mdp_mixer_write_cfg(struct mdss_mdp_mixer *mixer,
		struct mdss_mdp_mixer_cfg *cfg);
static void __mdss_mdp_reset_mixercfg(struct mdss_mdp_ctl *ctl);
@@ -476,7 +485,7 @@ u32 mdss_mdp_perf_calc_smp_size(struct mdss_mdp_pipe *pipe,
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	u32 smp_bytes;

	if (pipe->type == PIPE_TYPE_CURSOR)
	if (pipe->type == MDSS_MDP_PIPE_TYPE_CURSOR)
		return 0;

	/* Get allocated or fixed smp bytes */
@@ -1087,7 +1096,8 @@ static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
			if (mdss_mdp_perf_is_overlap(y0, y1, pipe->dst.y,
				(pipe->dst.y + pipe->dst.h)))
				bw_max_region += bw_overlap[j];
			pr_debug("v[%d](%d,%d)pipe[%d](%d,%d)bw(%llu %llu)\n",
			pr_debug("pipe%d rect%d: v[%d](%d,%d)pipe[%d](%d,%d)bw(%llu %llu)\n",
				pipe->num, pipe->multirect.num,
				i, y0, y1, j, pipe->dst.y,
				pipe->dst.y + pipe->dst.h, bw_overlap[j],
				bw_max_region);
@@ -3846,7 +3856,13 @@ static void mdss_mdp_pipe_reset(struct mdss_mdp_mixer *mixer, bool is_recovery)
	for_each_set_bit_from(bit, &pipe_map, MAX_PIPES_PER_LM) {
		struct mdss_mdp_pipe *pipe;

		pipe = mdss_mdp_pipe_search(mdata, 1 << bit);
		/*
		 * this assumes that within lm there can be either rect0+rect1
		 * or rect0 only. Thus to find the hardware pipe to halt only
		 * check for rect 0 is sufficient.
		 */
		pipe = mdss_mdp_pipe_search(mdata, 1 << bit,
				MDSS_MDP_PIPE_RECT0);
		if (pipe) {
			mdss_mdp_pipe_fetch_halt(pipe, is_recovery);
			if (sw_rst_avail)
@@ -4048,8 +4064,9 @@ void mdss_mdp_set_roi(struct mdss_mdp_ctl *ctl,
	}
}

static void __mdss_mdp_mixer_update_cfg_masks(u32 pnum, u32 stage,
		struct mdss_mdp_mixer_cfg *cfg)
static void __mdss_mdp_mixer_update_cfg_masks(u32 pnum,
		enum mdss_mdp_pipe_rect rect_num,
		u32 stage, struct mdss_mdp_mixer_cfg *cfg)
{
	u32 masks[NUM_MIXERCFG_REGS] = { 0 };
	int i;
@@ -4057,9 +4074,14 @@ static void __mdss_mdp_mixer_update_cfg_masks(u32 pnum, u32 stage,
	if (pnum >= MDSS_MDP_MAX_SSPP)
		return;

	if (rect_num == MDSS_MDP_PIPE_RECT0) {
		masks[0] = mdss_mdp_hwio_mask(&mdp_pipe_hwio[pnum].base, stage);
		masks[1] = mdss_mdp_hwio_mask(&mdp_pipe_hwio[pnum].ext, stage);
		masks[2] = mdss_mdp_hwio_mask(&mdp_pipe_hwio[pnum].ext2, stage);
	} else { /* RECT1 */
		masks[2] = mdss_mdp_hwio_mask(&mdp_pipe_rec1_hwio[pnum].ext2,
				stage);
	}

	for (i = 0; i < NUM_MIXERCFG_REGS; i++)
		cfg->config_masks[i] |= masks[i];
@@ -4142,9 +4164,9 @@ static void __mdss_mdp_mixer_write_cfg(struct mdss_mdp_mixer *mixer,
	__mdss_mdp_mixer_write_layer(mixer->ctl, mixer_num,
			vals, ARRAY_SIZE(vals));

	pr_debug("mixer=%d cfg=0%08x cfg_extn=0x%08x\n",
		mixer->num, vals[0], vals[1]);
	MDSS_XLOG(mixer->num, vals[0], vals[1]);
	pr_debug("mixer=%d cfg=0%08x cfg_extn=0x%08x cfg_extn2=0x%08x\n",
		mixer->num, vals[0], vals[1], vals[2]);
	MDSS_XLOG(mixer->num, vals[0], vals[1], vals[2]);
}

static void __mdss_mdp_reset_mixercfg(struct mdss_mdp_ctl *ctl)
@@ -4180,7 +4202,8 @@ bool mdss_mdp_mixer_reg_has_pipe(struct mdss_mdp_mixer *mixer,
	for (i = 0; i < NUM_MIXERCFG_REGS; i++)
		cfgs[i] = mdss_mdp_ctl_read(mixer->ctl, offs[i]);

	__mdss_mdp_mixer_update_cfg_masks(pipe->num, -1, &mixercfg);
	__mdss_mdp_mixer_update_cfg_masks(pipe->num, pipe->multirect.num, -1,
			&mixercfg);
	for (i = 0; i < NUM_MIXERCFG_REGS; i++) {
		if (cfgs[i] & mixercfg.config_masks[i]) {
			MDSS_XLOG(mixer->num, cfgs[0], cfgs[1]);
@@ -4277,7 +4300,8 @@ static void mdss_mdp_mixer_setup(struct mdss_mdp_ctl *master_ctl,
		mixercfg.border_enabled = true;
	} else {
		__mdss_mdp_mixer_update_cfg_masks(pipe->num,
				MDSS_MDP_STAGE_BASE, &mixercfg);
				pipe->multirect.num, MDSS_MDP_STAGE_BASE,
				&mixercfg);

		if (pipe->src_fmt->alpha_enable)
			bg_alpha_enable = 1;
@@ -4291,9 +4315,9 @@ static void mdss_mdp_mixer_setup(struct mdss_mdp_ctl *master_ctl,

		stage = i / MAX_PIPES_PER_STAGE;
		if (stage != pipe->mixer_stage) {
			pr_err("pipe%d mixer:%d mixer:%d stage mismatch. pipe->mixer_stage=%d, mixer->stage_pipe=%d. skip staging it\n",
			    pipe->num, mixer->num, mixer->num,
			    pipe->mixer_stage, stage);
			pr_warn("pipe%d rec%d mixer:%d stage mismatch. pipe->mixer_stage=%d, mixer->stage_pipe=%d multirect_mode=%d. skip staging it\n",
			    pipe->num, pipe->multirect.num, mixer->num,
			    pipe->mixer_stage, stage, pipe->multirect.mode);
			mixer->stage_pipe[i] = NULL;
			continue;
		}
@@ -4378,7 +4402,8 @@ static void mdss_mdp_mixer_setup(struct mdss_mdp_ctl *master_ctl,
		if (!pipe->src_fmt->alpha_enable && bg_alpha_enable)
			mixer_op_mode = 0;

		__mdss_mdp_mixer_update_cfg_masks(pipe->num, stage, &mixercfg);
		__mdss_mdp_mixer_update_cfg_masks(pipe->num,
				pipe->multirect.num, stage, &mixercfg);

		trace_mdp_sspp_change(pipe);

+51 −18
Original line number Diff line number Diff line
@@ -1074,6 +1074,23 @@ static void __dump_pipe(struct seq_file *s, struct mdss_mdp_pipe *pipe)
	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);
	if (pipe->multirect.max_rects > 1) {
		const char const *fmodes[] = {
			[MDSS_MDP_PIPE_MULTIRECT_PARALLEL]	= "parallel",
			[MDSS_MDP_PIPE_MULTIRECT_SERIAL]	= "serial",
			[MDSS_MDP_PIPE_MULTIRECT_NONE]		= "single",
		};
		const char *mode = NULL;

		if (pipe->multirect.mode < ARRAY_SIZE(fmodes))
			mode = fmodes[pipe->multirect.mode];
		if (!mode)
			mode = "invalid";

		seq_printf(s, "\trect=%d/%d fetch_mode=%s\n",
				pipe->multirect.num, pipe->multirect.max_rects,
				mode);
	}

	format = pipe->src_fmt->format;
	seq_printf(s, "\tsrc w=%d h=%d format=%d (%s)\n",
@@ -1403,10 +1420,39 @@ static void __stats_ctl_dump(struct mdss_mdp_ctl *ctl, struct seq_file *s)
	}
}

static void __dump_stat(struct seq_file *s, char *ptypestr,
		struct mdss_mdp_pipe *pipe_list, int count)
{
	struct mdss_mdp_pipe *pipe;
	int i = 0, ndx = 0;
	u32 rects_per_pipe = 1;

	while (i < count) {
		pipe = pipe_list + ndx;
		rects_per_pipe = pipe->multirect.max_rects;

		if (rects_per_pipe == 1)
			seq_printf(s, "%s%d", ptypestr, i);
		else
			seq_printf(s, "%s%d.%d", ptypestr, i,
					ndx % rects_per_pipe);

		seq_printf(s, " :   %08u\t", pipe->play_cnt);

		if ((++ndx % rects_per_pipe) == 0)
			i++;

		if ((ndx % 4) == 0)
			seq_puts(s, "\n");
	}

	if ((ndx % 4) != 0)
		seq_puts(s, "\n");
}

static int mdss_debugfs_stats_show(struct seq_file *s, void *v)
{
	struct mdss_data_type *mdata = (struct mdss_data_type *)s->private;
	struct mdss_mdp_pipe *pipe;
	int i;

	seq_puts(s, "\nmdp:\n");
@@ -1415,23 +1461,10 @@ static int mdss_debugfs_stats_show(struct seq_file *s, void *v)
		__stats_ctl_dump(mdata->ctl_off + i, s);
	seq_puts(s, "\n");

	for (i = 0; i < mdata->nvig_pipes; i++) {
		pipe = mdata->vig_pipes + i;
		seq_printf(s, "VIG%d :   %08u\t", i, pipe->play_cnt);
	}
	seq_puts(s, "\n");

	for (i = 0; i < mdata->nrgb_pipes; i++) {
		pipe = mdata->rgb_pipes + i;
		seq_printf(s, "RGB%d :   %08u\t", i, pipe->play_cnt);
	}
	seq_puts(s, "\n");

	for (i = 0; i < mdata->ndma_pipes; i++) {
		pipe = mdata->dma_pipes + i;
		seq_printf(s, "DMA%d :   %08u\t", i, pipe->play_cnt);
	}
	seq_puts(s, "\n");
	__dump_stat(s, "VIG", mdata->vig_pipes, mdata->nvig_pipes);
	__dump_stat(s, "RGB", mdata->rgb_pipes, mdata->nrgb_pipes);
	__dump_stat(s, "DMA", mdata->dma_pipes, mdata->ndma_pipes);
	__dump_stat(s, "CURSOR", mdata->cursor_pipes, mdata->ncursor_pipes);

	return 0;
}
Loading